Scala 无法使用函数API执行并行计算
我试图实现并行性章节红皮书中的Scala 无法使用函数API执行并行计算,scala,functional-programming,Scala,Functional Programming,我试图实现并行性章节红皮书中的countWords函数。当我将一个线程池传递给函数,并修改函数以打印包含单词的线程时,我只能看到打印的主线程。这表明我无法使此函数并行执行 我目前拥有的: type Par[A] = ExecutorService => Future[A] def asyncF[A, B](f: A => B): A => Par[B] = a => lazyUnit(f(a)) def lazyUnit[A](a: => A): Par[A]
countWords
函数。当我将一个线程池传递给函数,并修改函数以打印包含单词的线程时,我只能看到打印的主线程。这表明我无法使此函数并行执行
我目前拥有的:
type Par[A] = ExecutorService => Future[A]
def asyncF[A, B](f: A => B): A => Par[B] = a => lazyUnit(f(a))
def lazyUnit[A](a: => A): Par[A] = fork(unit(a))
def unit[A](a: A): Par[A] = (_: ExecutorService) => UnitFuture(a)
def fork[A](a: => Par[A]): Par[A] =
es => es.submit(new Callable[A] {
def call = a(es).get
})
def countWords(l: List[String]): Par[Int] = map(sequence(l.map(asyncF {
println(Thread.currentThread())
s => s.split(" ").length
})))(_.sum)
当我跑步时:
val listPar = List("ab cd", "hg ks", "lh ks", "lh hs")
val es = Executors.newFixedThreadPool(4)
val counts = countWords(listPar)(es)
println(counts.get(100, SECONDS))
我得到:
Thread[main,5,main]
8
我希望看到列表中每个元素都打印一个线程(因为有四个元素和一个大小为4的线程池),但是我只能看到打印的主线程
有什么建议吗?
谢谢在提问时,我想从一条建议开始——你应该始终提供一条建议。你的代码没有编译;例如,我不知道
UnitFuture
来自何处,我不知道您正在使用的sequence
的实现是什么,等等
下面是一个使用标准Scala的代码片段。首先,解释:
方法countWords
获取要计数的字符串列表,以及两个服务—一个用于处理不同线程上的Java未来,另一个用于处理不同线程上的Scala未来。Scala one是通过ExecutionContext.fromExecutor
方法从Java one派生而来的
为什么同时使用Java和Scala?嗯,我想保留Java,因为这是您最初编写代码的方式,但我不知道如何对Java的未来进行排序。所以我所做的是:
- 对于每个子字符串:
- fork是Java未来的任务
- 把它变成Scala的未来
- 对获得的Scala期货列表进行排序
import java.util.concurrent.{Callable, ExecutorService, Executors}
import java.util.concurrent.{Future => JFuture}
import scala.concurrent.{ExecutionContext, Future}
def scalaFromJavaFuture[A](
javaFuture: JFuture[A]
)(implicit ec: ExecutionContext): Future[A] =
Future { javaFuture.get }(ec)
def fork(s: String)(es: ExecutorService): java.util.concurrent.Future[Int] =
es.submit(new Callable[Int] {
def call = {
println(s"Thread: ${Thread.currentThread()}, processing string: $s")
s.split(" ").size
}
})
def countWords(l: List[String])(es: ExecutorService)(implicit ec: ExecutionContext): Future[Int] = {
val listOfFutures = l.map(elem => scalaFromJavaFuture(fork(elem)(es)))
Future.sequence(listOfFutures).map(_.sum)
}
val listPar = List("ab cd", "hg ks", "lh ks", "lh hs")
val es = Executors.newFixedThreadPool(4)
implicit val ec = ExecutionContext.fromExecutor(es)
val counts = countWords(listPar)(es)
counts.onComplete(println)
示例输出:
线程:线程[pool-1-Thread-1,5,main],处理字符串:ab-cd线程:线程[pool-1-Thread-3,5,main],处理字符串:hg-ks
线程:线程[pool-1-Thread-2,5,main],处理字符串:lh-ks
线程:线程[pool-1-Thread-4,5,main],处理字符串:lh-hs
成功(8) 注意,由执行上下文决定线程。运行几次,您将自己看到-您可能最终只使用了两个线程: 线程:线程[pool-1-Thread-1,5,main],处理字符串:ab-cd
线程:线程[pool-1-Thread-3,5,main],处理字符串:hg-ks
线程:线程[pool-1-Thread-1,5,main],处理字符串:lh-ks
线程:线程[pool-1-Thread-1,5,main],处理字符串:lh-hs
成功(8)
这方面有什么进展吗?正如您在代码示例中所说的那样,
println
表达式不应该放在countWords
函数中。通过在fork
中的call
方法中放置表达式,我可以看到此计算中涉及的所有线程。