Java ExecutorService - 有时比顺序处理慢?

时间:2013-09-19 18:25:47

标签: java multithreading performance executorservice

我正在编写一个简单的实用程序,它接受一组Callable任务,并且并行运行它们。希望是所花费的总时间比最长的任务花费的时间少。该实用程序还添加了一些错误处理逻辑 - 如果任何任务失败,并且失败是可以被视为“可重试”的东西(例如超时或用户指定的异常),那么我们直接运行任务。 / p>

我已经在ExecutorService周围实现了这个实用程序。分为两部分:

  1. 将所有Callable任务提交给ExecutorService,存储Future对象。
  2. 在for循环中,get()是每个Future的结果。如果出现异常,请执行“可重试”逻辑。
  3. 我编写了一些单元测试,以确保使用此实用程序比按顺序运行任务更快。对于每个测试,我会生成一定数量的Callable,每个Callable实际上在一个边界内的随机时间内执行Thread.sleep()。我尝试了不同的超时,不同数量的任务等,实用程序似乎胜过顺序执行。

    但是当我将它添加到需要这种实用程序的实际系统时,我看到结果变化很大 - 有时并行执行速度更快,有时速度更慢,有时速度更快,但仍然需要很多比最长的个人任务更多的时间。

    我只是做错了吗?我知道ExecutorService有invokeAll()但是吞下了底层的异常。我还尝试使用CompletionService按照它们完成的顺序获取任务结果,但它表现出或多或少相同的行为。我现在正在阅读闩锁和障碍 - 这是解决这个问题的正确方向吗?

2 个答案:

答案 0 :(得分:3)

  

我编写了一些单元测试,以确保使用此实用程序比按顺序运行任务更快。对于每个测试,我会生成一定数量的Callable,每个Callable都在一个绑定的

中随机执行一个Thread.sleep()

是的,这肯定不是一个公平的测试,因为它既不使用CPU也不使用IO。我当然希望希望并行睡眠比串行睡眠更快。 : - )

  

但是当我将它添加到需要这种实用程序的实际系统时,我看到了变化很大的结果

右。线程应用程序是否比串行应用程序运行得更快取决于许多因素。特别是,IO绑定应用程序将提高性能,因为它们受IO通道的约束,因此实际上无法执行并发操作。应用程序所需的处理越多,将其转换为多线程的胜利就越大。

  

我只是做错了吗?

很难知道没有更多细节。您可以考虑使用并发运行的线程数。如果要处理大量作业,则不应使用Executos.newCachedThreadPool()并根据架构所具有的CPU数量优化newFixedSizeThreadPool(...)

您还可能希望了解是否可以在几个线程中隔离IO操作以及将处理隔离到其他线程。就像一个输入线程从文件读取和一个输出线程(或一对)写入数据库或其他东西。因此,对于不同类型的任务,多个大小的池可能会做得更好,而不是使用单个线程池。

  

尝试使用CompletionService按照完成的顺序获取任务结果

如果您正在重试操作,那么使用CompletionService就是最佳选择。当作业完成并抛出异常(或返回失败)时,可以重新启动它们并立即将它们放回到线程池中。我认为没有任何理由可以解决您的性能问题。

答案 1 :(得分:3)

多线程编程不是免费的。它有一个开销。头顶很容易超过并且性能提升,并且通常会使代码更复杂。

其他线程可以访问更多cpu电源(假设您有备用cpu),但一般情况下它们不会让你更快地旋转硬盘,给你更多的网络带宽或加速不受cpu限制的东西。

多线程可以帮助您获得更多的外部资源。