首页 文章

Scala,使用Responder抽象可能的异步计算

提问于
浏览
0

我一直在研究scala和AKKA来管理一个明显可并行化的算法 . 我对函数式编程有一些了解,而且大部分都是Java,所以我的FP可能还不是最好的 .

我正在使用的算法非常简单,有一个顶级计算:

def computeFull(...): FullObject

此计算调用子计算,然后将其求和(以简化):

def computePartial(...): Int

computeFull 做这样的事情(再次简化):

val partials = for(x <- 1 to 10
     y <- 1 to 10) yield computePartial(x, y)
 partials.foldLeft(0)(_ + _)

因此,它非常接近AKKA示例,进行PI计算 . 我有很多可以调用的computeFull,并且每个都有很多computePartial . 所以我可以在AKKA演员中包装所有这些,或者简化Futures,在不同的线程中调用每个computeFull和每个computePartial . 然后我可以使用http://doc.akka.io/docs/akka/snapshot/scala/futures.html的折叠,拉链和 Map 功能来组合未来 .

但是,这意味着computeFull和computePartial必须返回包含实际结果的Futures . 因此,它们依赖于AKKA并假设事物并行运行 . 实际上,我还必须在函数中隐式传递执行上下文 .

我认为这很奇怪,算法“不应该”知道它是如何并行化的细节,或者它是否 .

在阅读了scala(而不是AKKA)中的Futures并查看Code Continuation之后 . 似乎scala(http://www.scala-lang.org/api/current/scala/Responder.html)提供的Responder monad似乎是抽象函数调用如何运行的正确方法 . 我有这种模糊的直觉,即computeFull和computePartial可以返回Responders而不是future,当monad执行时,它决定嵌入在Responder中的代码是如何执行的(如果它生成一个新的actor或者它是在同一个线程上执行的) ) .

但是,我不确定如何得到这个结果 . 有什么建议?你觉得我走的是正确的吗?

2 回答

  • 0

    如果你不想依赖Akka(但请注意,Akka风格的未来将被移动并包含在Scala 2.10中)并且你的计算是一个简单的折叠,你可以简单地使用Scala的并行集合:

    val partials = for { x <- (1 to 10).par
      y <- 1 to 10
    } yield computePartial(x, y)
    // blocks until everything is computed
    partials.foldLeft(0)(_ + _)
    

    当然,这将阻止,直到 partials 准备就绪,所以当你真的需要期货时,这可能不是一个合适的情况 .

    使用Scala 2.10样式期货,您可以完全异步,而无需您的算法注意到它:

    def computePartial(x: Int, y: Int) = {
      Thread.sleep((1000 * math.random).toInt)
      println (x + ", " + y)
      x * y
    }
    
    import scala.concurrent.future
    import scala.concurrent.Future
    val partials: IndexedSeq[Future[Int]] = for {
      x <- 1 to 10
      y <- 1 to 10
    } yield future(computePartial(x, y))
    
    val futureResult: Future[Int] = Future.sequence(partials).map(_.fold(0)(_ + _))
    
    def useResult(result: Int) = println(s"The sum is $result")
    
    // now I want to use the result of my computation
    futureResult map { result => // called when ready
      useResult(result)
    }
    // still no blocking
    println("This is probably printed before the sum is calculated.")
    

    所以, computePartial 不需要知道它是如何被执行的 . (它不应该有任何副作用,即使为了这个例子的目的,包括了 println 副作用 . )

    可能的 computeFull 方法应该管理算法,因此了解 Futures 或并行性 . 毕竟这是算法的一部分 .

    (至于 Responder :Scala的旧期货使用它,所以我不知道这是怎么回事 . - 并不是一个执行上下文正是你正在寻找的配置方式?)

  • 3

    akka中的单身演员不知道他是否以平行方式奔跑 . 这就是akka的设计方式 . 但是如果你不想依赖akka,你可以使用并行集合,如:

    for (i <- (0 until numberOfPartialComputations).par) yield (
      computePartial(i)
    ).sum
    

    在并行集合上调用和,并且以并行方式执行 .

相关问题