了解Scalaz Future和Task的一点帮助

时间:2013-10-30 19:52:34

标签: scala asynchronous concurrency scalaz scalaz7

我正在尝试理解scalaz并发包(主要是Future和Task类)背后的想法和目的,但是当在某些应用程序中使用它们时,它现在远非简单的顺序模拟,而scala.concurrent.Future则更有效更好。任何人都可以分享他使用scalaz编写并发/异步应用程序的经验,基本上如何正确使用它的async方法?据我所知,来源async不使用单独的线程,例如调用标准future或scalaz工作的fork/apply方法,所以为什么它被称为async然后?这是否意味着为了通过scalaz获得真正的并发性,我总是要调用fork(now(...))apply

4 个答案:

答案 0 :(得分:17)

我不是斯卡拉斯专家,但我会尽力帮助你。让我试着逐一回答你的问题:

1)任何人都可以分享他使用scalaz编写并发/异步应用程序的经验,基本上如何正确使用它的异步方法?

我们先来看看async签名:

def async[A](listen: (A => Unit) => Unit): Future[A]

一开始可能有点神秘,所以一如既往地查看测试以了解可能的用例是个好主意。在https://github.com/scalaz/scalaz/blob/scalaz-seven/tests/src/test/scala/scalaz/concurrent/FutureTest.scala 你可以找到以下代码:

"when constructed from Future.async" ! prop{(n: Int) =>
  def callback(call: Int => Unit): Unit = call(n)
  Future.async(callback).run must_==   
}

正如我们从签名Future.async所知,只需使用签名(A => Unit) => Unit的功能构建新的Future。这真正意味着Future.async作为参数函数,对于给定的回调进行所有必需的计算并将结果传递给该回调。
重要的是要注意Future.async本身不运行任何计算,它只准备结构以便稍后运行它们。

2)据我所知,async不使用单独的线程,比如调用标准的future,或者scalaz的fork / apply方法,那么为什么它被称为async呢?

你是对的。只有forkapply似乎使用线程运行任何内容,这很容易注意到包含implicit pool: ExecutorService的签名。我不能在这里为作者说话,但我猜async与回调有关。这意味着不是阻止Future在最后获得结果,而是使用异步回调。

3)这是否意味着为了通过scalaz获得真正的并发性,我总是必须调用fork(now(...))或者应用?

我可以说,是的。请注意,当您使用语法Future(x)创建Future时,您在此处使用apply方法,因此这是一种默认行为(很好)。

如果您想更好地了解Scalaz Futures的设计,我建议您阅读"Functional Programming in Scala"。我相信本书是由主要的Scalaz贡献者编写的,第7章讨论了为纯函数并行库设计API。它与Scalaz Future不完全相同,但你可以看到很多相似之处。

答案 1 :(得分:2)

您还可以阅读有关Scalaz任务和未来的精彩Timothy Perrett blog post,其中包含许多不那么明显的细节。

答案 2 :(得分:1)

async用于将基于回调的异步API调整为Future。它被称为async,因为它预计它将与异步运行的东西一起使用,或许可以从另一个线程的某个地方调用回调。这是真实的"并发性,只要您调用的API确实异步使用它(例如,我将Future.async与AWS SDK的异步部分一起使用,如AmazonSimpleDBAsyncClient)。

如果你想要"真实"直接来自scalaz Task API的并发性需要使用forkgatherUnordered之类的东西,因为许多API默认为安全/确定性和可重新启动,只有在明确请求时才具有并发性。

答案 3 :(得分:1)

使用map和flatMap编写任务时,可以通过不使用fork获得性能提升,请参阅:

http://blog.higher-order.com/blog/2015/06/18/easy-performance-wins-with-scalaz/