我是Scala的新手,尤其是Actors,我的问题是如此基本,我发现的在线资源并没有涵盖它。
我有一个CPU密集型,易于并行化的算法,它将在 n 核心机器上运行(我不知道 n )。如何在Actors中实现这一点,以便所有可用的内核解决问题?
我想到的第一种方法是简单地将问题分解为 m 件(其中 m 是一些中等数字,如10,000)并创建 m 演员,每件一件,给每个演员一个小片,让他们去吧。
不知何故,这让我觉得效率低下。数以万计的演员只是闲逛,等待一些CPU爱,毫无意义地切换上下文...
然后我想,制作一些数量较少的演员,然后每个演员送几件。问题是,没有理由期望这些部分的大小相同,因此一个核心可能会陷入困境,其中许多任务仍然排队,而其他核心则处于空闲状态。
我和一位知道哪位演员忙碌的主管在一起,并最终意识到这必须是一个已解决的问题。必须有一个标准模式(甚至可能是标准库)来处理这个非常通用的问题。有什么建议吗?
答案 0 :(得分:8)
查看Akka库,其中包含actor的实现。 Dispatchers Module为您提供了更多选项,可以将actor限制为cpu线程(基于HawtDispatch的事件驱动)和/或平衡工作负载(基于工作窃取事件)。
答案 1 :(得分:3)
你应该看看我认为的期货。实际上,您可能需要一个线程池,它只是在达到最大线程数时对线程进行排队。
这是一个涉及期货的小例子:http://blog.tackley.net/2010/01/scala-futures.html
我还建议你不要过多关注上下文切换,因为除了依赖底层实现你真的不能做任何事情。当然,经验法则是将活动线程保持在物理核心数量的周围,但正如我上面提到的,这可以由具有fifo队列的线程池处理。
请注意,我不知道一般的演员或期货是否都是用这种游泳池实现的。
对于线程池,请查看:http://www.scala-lang.org/api/current/scala/concurrent/ThreadPoolRunner.html
也许这样:http://www.scala-lang.org/api/current/scala/actors/scheduler/ResizableThreadPoolScheduler.html
祝你好运修改强>
使用期货查看这段代码:
import scala.actors.Futures._
object FibFut {
def fib(i: Int): Int = if (i < 2) 1 else fib(i - 1) + fib(i - 2)
def main(args: Array[String]) {
val fibs = for (i <- 0 to 42) yield future { fib(i) }
for (future <- fibs) println(future())
}
}
它展示了关于期货的一个非常好的观点,即你决定接收结果的顺序(而不是使用fifo系统的正常邮箱系统,即最快的演员发送他的结果第一)。
答案 2 :(得分:3)
通常,有2种角色:与线程相关的角色(每个角色一个线程),以及共享1+线程的角色,在分配资源的调度程序/调度程序后面工作(=执行任务的可能性) /处理受控线程池或单个线程的传入消息)。
我假设你使用第二种类型的演员 - 事件驱动的演员,因为你提到你运行了10k。无论你拥有多少事件驱动的演员(数千或数百万),他们都将为小线程池争取处理消息。因此,您甚至会将性能更差的任务队列划分为大量的部分 - 调度程序将尝试处理针对固定线程池发送给10k actor的消息(这很慢),或者将在池中分配新线程(如果池没有限制),这是危险的(在最坏的情况下,将启动10k个线程来处理消息)。
事件驱动的角色适合短时间(理想情况下,非阻塞)任务。如果您正在处理CPU密集型任务,我会限制调度程序/调度程序池中的线程数(当您使用事件驱动的actor时)或者actor本身(当您使用基于线程的actor时)将内核数量限制为达到最佳表现。
如果您希望自动完成此操作(将调度程序池中的线程数调整为核心数),则应使用 HawtDisaptch (或 {{3正如之前提出的那样:):
'HawtDispatcher'使用 HawtDispatch线程库哪个 是libdispatch的Java克隆。所有 有这种调度员的演员 在一个系统范围内执行 固定大小的线程池。的数量 线程的数量将匹配 您的系统上可用的核心。该 调度员将消息传递给 演员按照他们的顺序 发件人的制作人。
答案 3 :(得分:0)
对于任何重要的项目,我通常都有一个主管演员,一组工人演员,每个演员都可以做任何必要的工作,还有大量的工作要做。虽然我经常这样做,但我从来没有把它放在(个人)库中,因为每次操作最终都是如此不同,而且与整个编码项目相比,开销非常小。
答案 4 :(得分:0)
Be aware of actor starvation如果你最终使用了一般的actor线程池。我最终只是使用我自己的algorithm-task-owned线程池来处理长时间运行的并发任务的并行化。
答案 5 :(得分:0)
即将推出的Scala 2.9预计将包含并行数据结构,这些数据结构应自动处理某些用途。虽然它不使用Actors,但可能需要考虑你的问题。
虽然此功能最初定于2.8,但它已被推迟到下一个主要版本。
最后一个ScalaDays的演示文稿在这里: