我有很多工作(数千个工作)供Scala应用程序处理。每件作品都是100 MB文件的文件名。要处理每个文件,我需要使用非线程安全的提取器对象(我可以有多个副本,但副本很昂贵,我不应该为每个作业创建一个)。在Scala中并行完成这项工作的最佳方法是什么?
答案 0 :(得分:2)
您可以将提取器包装在Actor中,并将每个文件名作为消息发送给actor。由于actor的实例一次只处理一条消息,因此线程安全不会成为问题。如果你想使用多个提取器,只需启动actor的多个实例并在它们之间取得平衡(你可以编写另一个actor作为负载均衡器)。
然后,提取器actor可以将提取的文件发送给其他actor,以便并行执行其余的处理。
答案 1 :(得分:1)
不要制作1000个作业,而是制作4x250作业(定位4个线程)并为每个批次提供一个提取器。在每批中,按顺序工作。这可能不是最佳的并行方式,因为一个批次可能更早完成,但它很容易实现。
可能正确(但更复杂)的解决方案是制作一个提取器池,其中作业从中提取器并在完成后将它们放回去。
答案 2 :(得分:0)
我会创建一个线程池,其中每个线程都有一个提取器类的实例,并实例化这些线程所需的数量,以使系统饱和(基于CPU使用率,IO带宽,内存带宽,网络带宽) ,争夺其他共享资源等)。然后使用线程安全的工作队列,这些线程可以从中提取任务,处理它们,并迭代直到容器为空。
请注意,几乎任何现代语言都应该有一个或几个库来实现这一点。在C ++中,它将是英特尔的线程构建模块。在Objective-C中,它将是Grand Central Dispatch。
答案 3 :(得分:0)
这取决于:每个作业的提取器消耗的CPU的相对数量是多少?
如果它非常小,您就会遇到经典的单生产者/多用户问题,您可以在其中找到许多不同语言的解决方案。对于Scala,如果您不愿意开始使用actor,您仍然可以使用Java API(Runnable,Executors和BlockingQueue,非常好)。
如果它是一个很大的数量(超过10%),你的应用程序永远不会使用多线程模型进行扩展(参见Amdhal法)。您可能更喜欢运行多个进程(多个JVM)来获得线程安全性,从而消除非顺序部分。
答案 4 :(得分:0)
第一个问题:工作需要多快完成?
第二个问题:这项工作是否会被隔离到一个物理盒中,或者你的计算资源上限是什么。
第三个问题:每个“工作”需要做的工作是否需要阻塞,是否已经序列化或者可以划分为并行工作包?
也许想想一个分布式模型,你可以通过设计来扩展设计,从第一个实例推出多个节点,演员,remoteref所有那些废话首先...尝试并保持你的逻辑简单和容易 - 如此序列化。不要只考虑一个盒子。
这里的大多数答案似乎都在关注产生线程池和执行器以及所有这些东西的复杂性 - 这很好,但是在开始使你的生活复杂化之前,请确保先处理真正的问题。围绕如何管理同步逻辑。
如果问题可以分解,则将其分解。不要为了这样做而过度复杂化 - 它会带来更好的工程代码和更少的不眠之夜。