理解Scalaz Future和Task的一点帮助

18

我试图理解scalaz并发包背后的思想和目的,主要是Future和Task类,但是当在一些应用程序中使用它们时,它现在远离简单的顺序模拟,而scala.concurrent.Future则更好地运行。有人能分享他们在scalaz编写并发/异步应用程序方面的经验吗?基本上如何正确使用它的async方法?从资源中我理解到async不像调用标准的future或scalaz的fork/apply方法那样使用单独的线程,那么为什么它被称为async呢?这是否意味着为了获得scalaz的真正并发性,我总是必须调用fork(now(...))apply

4个回答

17

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

1)有谁能分享使用scalaz编写并发/异步应用程序的经验,基本上如何正确使用它的async方法?

首先让我们看一下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方法那样使用单独的线程,那么为什么它被称为异步?

你是正确的。只有forkapply似乎使用线程运行任何内容,这很容易通过包含implicit pool: ExecutorService的签名来注意到。我无法代表作者在这里发言,但我想异步与回调有关。这意味着您将使用异步回调,而不是阻塞在Future上以在最后获取结果。

3)这是否意味着为了获得scalaz的实际并发性,我总是要调用fork(now(...))或apply?

据我所知,是的。只需注意,当您使用语法Future(x)创建Future时,您在这里使用了apply方法,因此这是默认行为(这很好)。

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


2

您还可以阅读 Timothy Perrett 的精彩博客文章,讨论了 Scalaz Task 和 Future 中的许多不太明显的细节。blog post


1
async用于将异步、基于回调的API适配为Future。它被称为async,因为预期它将与某些运行异步的东西一起使用,可能会在后面的某个线程中调用回调函数。只要你调用的API确实异步使用(例如,我使用Future.async与AWS SDK的异步部分一起使用,如AmazonSimpleDBAsyncClient),这就是“真正”的并发。
如果您直接从scalaz Task API中想要“真正”的并发,则需要使用诸如forkgatherUnordered之类的内容,因为许多API默认为安全/确定性和可重启性,仅在明确请求时才进行并发处理。

1

2
这个答案可以通过引用博客并在此处包含相关信息来改进。未来无法依赖于一个博客的存在。 - AJ X.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接