Scalaz任务无法启动

时间:2018-01-31 00:29:08

标签: scala task yield scalaz

我试图使用scalaz Task进行异步调用。

由于某些奇怪的原因,每当我尝试调用methodA时,虽然我得到一个scalaz.concurrent.Task返回但我从未看到第二个print语句让我相信永远不会返回异步调用。为了让我开始这项任务,是否有一些我不想要的东西?

for {
    foo <- println("we are in this for loop!").asAsyncSuccess()
    authenticatedUser <- methodA(parameterA)
    foo2 <- println("we are out of this this call!").asAsyncSuccess()
} yield {
    authenticatedUser
}


def methodA(parameterA: SomeType): Task[User]

1 个答案:

答案 0 :(得分:0)

首先,Scalaz Task很懒:当你创建它或从某种方法获取它时它不会启动。它是设计使得Task能够很好地结合起来。在您将整个程序完全组合到单个主Task之前,它无意启动,所以当您完成后,您需要使用Task方法之一手动启动聚合的perform ,就像unsafePerformSync那样等待当前线程上聚合异步计算的结果:

(for {
    foo <- println("we are in this for loop!").asAsyncSuccess()
    authenticatedUser <- methodA(parameterA)
    foo2 <- println("we are out of this this call!").asAsyncSuccess()
} yield {
    authenticatedUser
}).unsafePerformSync

从原始代码中可以看出,您从未启动任何Task。但是,您已经提到第一个println将其消息打印到控制台。这可能与asAsyncSuccess方法有关:我没有在Scalaz中找到它,所以我假设它在代码中的某个隐式类中:

implicit class TaskOps[A](val a: A) extends AnyVal {
  def asAsyncSuccess(): Task[A] = Task(a)
}

如果您编写一个这样的帮助器隐式类,它将不会将有效表达式转换为惰性Task操作,尽管Task.applycall-by-name。它只会转换其结果,恰好是Unit,因为它自己的参数a不是按名称调用的。要按预期工作,它必须如下所示:

implicit class TaskOps[A](a: => A) {
  def asAsyncSuccess(): Task[A] = Task(a)
}

您也可能会问为什么第一个println打印出来的东西,而第二个不是。这与for-comprehensions desugaring方法调用有关。具体来说,编译器将您的代码转换为:

println("we are in this for loop!").asAsyncSuccess().flatMap(foo =>
  methodA(parameterA).flatMap(authenticatedUser =>
    println("we are out of this this call!").asAsyncSuccess().map(foo2 =>
      authenticatedUser)))

如果asAsyncSuccess不符合预期的Task语义,则会立即执行println。但是它的结果然后被包装到Task中,它本质上只是一个包含在start函数上的包装器,而flatMap实现只是将这些函数组合在一起而不运行它们。因此,在您调用methodA或其他println辅助方法之前,unsafePerformSync或第二perform将不会执行。但请注意,根据println语义,第二个Task仍然会比它应该更早执行,而不是那个