单元组是一种排序计算的机制,下面的列表虽然是按照随机顺序打印的,但还是一个单元组吗?

问题描述 投票:0回答:1
for {
    i <- 1 to 5
  } yield Future(println(i))

Desugared to:

List(1,2,3,4,5).map {i => Future(println(i))}

上述代码打印的数字是 随机顺序.

现在,如果我们看到Monad的多种定义。a)Monad是一个对象的包装器。b) 单元组是一种排序计算的机制。

我想回答的问题是,对List单体的map操作是不是应该等待列表中的第一个元素被打印出来,然后才去计算第二个元素,而不考虑Future?

对不起,这可能很简单,我把它复杂化了,但对我来说,要找到简单的推理会变得更棘手。希望能得到答案:)

scala monads future sequential for-comprehension
1个回答
7
投票

比较。

for {
  _ <- Future(println(1))
  _ <- Future(println(2))
  _ <- Future(println(3))
  _ <- Future(println(4))
  _ <- Future(println(5))
} yield ()

Future(println(1)).flatMap { _ =>
  Future(println(2))
}.flatMap { _ =>
  Future(println(3))
}.flatMap { _ =>
  Future(println(4))
}.flatMap { _ =>
  Future(println(5))
}

List(
  Future(println(1)),
  Future(println(2)),
  Future(println(3)),
  Future(println(4)),
  Future(println(5))
)

前两个创造下一个 Future 只有在前者完成并提供结果后,才可以使用。最后一个是创建所有的 Future(在这一点上,它与您的例子中的 List[Future]).

Future (与 IO 来自猫咪效应,Monix的 Task 或ZIO)是急切的,所以它在你创建它的时候就开始执行。出于这个原因,你在前两个例子中的结果是顺序的,而在第三个例子中的结果是随机顺序(竞赛条件)。

如果你使用 IO 而不是 Future 这将是更明显的,因为你不可能只拥有 List[IO[Unit]] 并执行副作用--你必须以某种方式将不同的IO组合成一个,而你这样做的方式将使效果是顺序的还是并行的变得很明显。

底线是--是否 Future 是一个单体,取决于 .flatMap 的行为(以及它在与 Future.successful),所以你的结果并不能使你的说法失效。Future 是一个单项式.如果你开始用异常检查它的行为,你可以有一些疑问。(如果你开始用异常检查它的行为,你会有一些疑问,但这是另一个话题)。


1
投票

map的执行确实是顺序的,但是当你把它包到Future时,它就会以异步的方式执行,我的意思是它会在另一个线程中被评估,正因为如此,不可能知道哪个线程会更早完成,因为它还取决于操作系统的线程管理和其他考虑因素。


1
投票

你的这两个代码片段从宽泛的角度来说还是Monads。当你做 .map() 在你的对象上,map按顺序一个一个地选取元素(从索引0到索引4),然后它将这些元素传递给操作块(这是map的主体--map是一个高阶函数,接受类型为f:This => That)。然后将其传递给一个操作块(它是map的主体--map是一个高阶函数,接受f:This => That类型的函数)。

所以单项式操作的责任是将其拾取并作为paramater传递给一个函数。

在你的例子中,实际的函数类型是。

f: Int => Future[Unit]

为了清楚起见,你的函数实际上是这样的。

def someFunction(i: Int): Future[Unit] = {
    Future {
        println(i)
    }
}

所以,映射操作在这里做的是它从你的对象中挑选出一个项目(按顺序,一个接一个) 然后调用someFunction(i). 这就是一个单体所做的一切。

现在来回答为什么你的 println 是随机的,这是因为 JVM线程.

如果你重新定义你的地图主体,就像这样。

List(1,2,3,4,5)
  .map {i =>
    println(s"Going to invoke the println in another thread for $i")
    Future(println(i))
  }

你会发现,第一个 println 将按顺序进行--始终如此! 它证明了 .map() 按顺序选择你的元素。而下一个 println 可能不按顺序,也可能不按顺序。这种失序的时尚并不是因为单体操作。map 但由于多核CPU的多线程特性。

© www.soinside.com 2019 - 2024. All rights reserved.