18

我试图了解 scalaz 并发包背后的想法和目的,主要是 Future 和 Task 类,但是在某些应用程序中使用它们时,它现在远非简单的顺序模拟,而scala.concurrent.Future, 工作得更好。任何人都可以分享他用scalaz编写并发/异步应用程序的经验,基本上如何async正确使用它的方法?正如我从消息来源了解到的那样,async它不使用单独的线程,例如对 standard 的调用future,或者fork/apply来自 scalaz 的方法,那么为什么要调用它async呢?这是否意味着为了与 scalaz 获得真正的并发性,我总是必须调用fork(now(...))or apply

4

4 回答 4

17

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

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

2)据我了解,异步不使用单独的线程,例如对标准未来的调用,或者来自 scalaz 的 fork/apply 方法有效,那么为什么将其称为异步呢?

你是对的。只有fork并且apply似乎正在使用线程运行任何东西,这很容易注意到查看包含implicit pool: ExecutorService. 我不能在这里代表作者发言,但我猜异步与回调有关。这意味着您将使用异步回调,而不是阻塞 Future 以获得最终结果。

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

据我所知,是的。请注意,当您使用语法创建 Future 时,您在这里Future(x)使用的是apply方法,所以这是一种默认行为(这很好)。

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

于 2013-12-28T12:28:30.070 回答
2

您还可以阅读关于 Scalaz 任务和未来的精彩的 Timothy Perrett博客文章,其中涵盖了许多不那么明显的细节。

于 2014-12-02T13:24:59.327 回答
1

async用于将基于回调的异步 API 改编为Future. 之所以调用它,是async因为预计它将与异步运行的东西一起使用,可能会从另一个线程中调用回调。这是“真正的”并发,前提是您调用的 API 确实异步使用它(例如,我使用Future.asyncAWS 开发工具包的异步部分,例如AmazonSimpleDBAsyncClient)。

如果你想Task直接从 scalaz API 获得“真正的”并发,你需要使用类似forkor之类gatherUnordered的东西,因为许多 API 默认是安全/确定性和可重新启动的,只有在明确请求时才具有并发性。

于 2014-12-02T13:33:09.633 回答
1

使用 map 和 flatMap 组合任务时,您可以通过不使用 fork 来获得性能优势,请参阅:

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

于 2016-01-06T14:06:48.153 回答