我正在编写一个简单的实用程序,它接受可调用任务的集合,并并行运行它们。我们希望所用的总时间比最长的任务所花费的时间少得多。该实用工具还添加了一些错误处理逻辑--如果任何任务失败,并且该故障可以被视为“可重试”(例如超时或用户指定的异常),那么我们直接运行该任务。
我已经围绕一个ExecutorService实现了这个实用程序。有两部分:
我编写了一些单元测试,以确保使用此实用程序比按顺序运行任务更快。对于每个测试,我都会生成一定数量的可调用函数,每个测试本质上都是在一个界限内执行一个随机时间的Thread.sleep()。我对不同的超时、不同数量的任务等进行了实验,而且这个实用程序的性能似乎优于顺序执行。
但是当我把它添加到需要这种实用工具的实际系统中时,我看到了变化很大的结果--有时并行执行更快,有时更慢,有时更快,但仍然比最长的单个任务花费更长的时间。
我只是做错了吗?我知道ExecutorService有invokeAll(),但这就吞噬了潜在的异常。我还尝试使用CompletionService来按照任务完成的顺序来获取任务结果,但是它显示了或多或少相同的行为。现在我正在阅读关于闩锁和障碍的文章--这是解决这个问题的正确方向吗?
发布于 2013-09-19 18:32:20
我编写了一些单元测试,以确保使用此实用程序比按顺序运行任务更快。对于每个测试,我都会生成一定数量的可调用程序,每个测试本质上都在绑定内执行一个随机时间的Thread.sleep()
是的,这肯定不是一个公平的测试,因为它既没有使用CPU,也没有使用IO。我当然希望平行睡眠比串行睡眠跑得更快。:-)
但是,当我将它添加到实际系统中时,需要这样的实用程序,我看到了非常可变的结果。
正确的。线程应用程序是否比串行应用程序运行得更快,这在很大程度上取决于许多因素。特别是,受IO绑定的应用程序将不会提高性能,因为它们受到IO通道的约束,因此实际上无法执行并发操作。应用程序所需的处理越多,win就越大,将其转换为多线程。
我只是做错了吗?
如果没有更多的细节就很难知道。您可以考虑使用并发运行的线程数。如果您有大量的任务要处理,您不应该使用Executos.newCachedThreadPool()
,而应该根据您的体系结构所拥有的CPU数量来优化newFixedSizeThreadPool(...)
。
您还可能希望了解是否可以将IO操作隔离在几个线程中,并将处理过程隔离到其他线程。就像一个从文件中读取的输入线程和一个写入数据库的输出线程(或一对)一样。因此,多个大小的池可以更好地处理不同类型的任务,而不是使用单个线程池。
尝试使用CompletionService以完成任务的顺序获取任务结果
如果您要重新尝试操作,那么使用CompletionService
就是正确的方法。当作业完成并抛出异常(或返回失败)时,它们可以重新启动并立即放入线程池中。我看不出为什么你的表现会因为这个而出现问题。
发布于 2013-09-19 18:38:12
多线程编程并不是免费的。它有一个开销。超越可以很容易超过和性能增益,通常会使您的代码更加复杂。
额外的线程可以访问更多的cpu (假设您有多余的cpu ),但通常它们不会使您的HDD旋转得更快,给您更多的网络带宽或加快一些不受cpu约束的东西。
多个线程可以帮助您更多地共享外部资源。
https://stackoverflow.com/questions/18902279
复制相似问题