在短时间内用Java执行数百万个任务?

5
我需要在Java中执行大约8,000,000个任务。每个任务的运行时间在1到50毫秒之间。我尝试使用循环串行执行这些任务,并使用ThreadPoolExecutor并行执行它们。显然,通过循环串行执行任务要慢得多,而通过ThreadPoolExecutor运行它们可以获得显着的性能提升。但是,我对ThreadPoolExecutor的性能仍不满意。
我能够在4个核心上使用15个线程运行所有8,000,000个任务。我将50,000个任务分批提交给ThreadPoolExecutor。我允许ExecutorCompletionService等待1000毫秒返回结果。经过调整我的应用程序参数后,我需要大约25分钟来处理所有8,000,000个任务。
是否有一种比25分钟更快的方式来运行我的应用程序,例如使用Hadoop(使用多台机器的分布式系统)?我可以使用其他技术或框架。

1
Hadoop或Cassandra可能会有所帮助,这取决于您是否遇到了Amdahl定律。您的任务是否可以更加高效? - Elliott Frisch
2
你可以将应用程序复制到10台机器上,将800万个任务分成10个部分,在这10台机器上点击“运行”按钮10次。 - jondinham
4
你确定你的程序是CPU限制吗? - Kevin Krumwiede
你是否在丢弃你创建的对象?有没有什么可以重复利用的东西? - Kalpesh Soni
每毫秒有8,000,000个操作,需要1.25 MHz的频率... 在我看来这是一个愚蠢的问题... - Martin Frank
显示剩余7条评论
2个回答

1

这个Akka教程展示了Akka如何帮助并行任务。

我没有使用Akka的实际经验,但我的理解是它可以根据部署时的配置(例如线程数、进程数、集群中的主机数量等)来扩展应用程序,而对任务实现的更改很小。

更多信息请参见维基百科:基于Akka actors的应用程序的关键点


0
为了找到最佳线程数,您必须查看各个任务。
如果任务专门利用内核,则没有其他任务可以在同一内核上执行。但是,大多数任务都具有一些IO元素,例如读取要处理的数据并将结果写回(假设您的任务是某些复杂计算)。
线程数应该大约为 '核心数量' x '利用率百分比',其中利用率百分比是介于零和一之间的调整参数。使用以下方式动态查找核心数:
int cores = Runtime.getRuntime().availableProcessors();

所以

int poolcount = Math.round( cores * utilizationFactor);

如果您需要进行扩展,可以选择水平或垂直扩展。

水平扩展,增加更多的核心,将调整吞吐量,但是如果任务之间存在过多的同步,则利用率可能不是线性的。

垂直扩展,增加更多的计算机,肯定会给您更多的核心来计算。因此,处理农场一直以来都很有趣,因为它比水平扩展更具成本效益。然而,分发成本和将数据分发到计算机进行计算的成本始终是瓶颈所在。

正如评论中提到的那样,Hadoop通过将数据分布在分区中并将计算发送到数据中来解决了这个问题。这对于简单合并类型的任务非常有效。

另外,Cassandra还提供了一个分布式数据库,其中分区写入通过提交日志处理,并且选择性读/写一致性。这基本上可以更快地移动您的数据,但我怀疑您并不太依赖它。

除了这些注意事项,您真的需要查看您的任务内部,了解它们是如何构思和实现的,特别是在分治性质或顺序/管道性质方面。正如建议的那样,Akka在吞吐异步任务方面提供了很多帮助,并且有助于同步障碍。

最后,我的最后一条建议是看看LMAX Disruptor(http://lmax-exchange.github.io/disruptor/)。这应该允许您在各个阶段之间传递工作负载,并具有非常高的吞吐量。这(连同最佳核心控制)可能会提高您的速度,而无需太多考虑情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接