【问题标题】:A little help on understanding Scalaz Future and Task对理解 Scalaz Future 和 Task 的一点帮助
【发布时间】:2013-11-10 15:16:36
【问题描述】:

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

【问题讨论】:

    标签: scala asynchronous concurrency scalaz scalaz7


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

          • 这个答案可以通过参考博客来改进,但在此处包含相关信息。没有办法依赖未来存在的博客。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-14
          • 2018-05-30
          • 1970-01-01
          • 1970-01-01
          • 2014-09-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多