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

标签 java multithreading performance executorservice

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

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

  1. 将所有 Callable 任务提交给 ExecutorService,存储 Future 对象。
  2. 在 for 循环中,get() 每个 Future 的结果。如果出现异常,请执行“可重试”逻辑。

我编写了一些单元测试,以确保使用此实用程序比按顺序运行任务更快。对于每个测试,我都会生成一定数量的 Callable,每个 Callable 本质上在一定范围内执行 Thread.sleep() 一段随机时间。我尝试了不同的超时、不同数量的任务等,该实用程序似乎优于顺序执行。

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

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

最佳答案

I wrote some unit tests to ensure that using this utility is faster than running the tasks in sequence. For each test, I'd generate a certain number of Callable's, each essentially performing a Thread.sleep() for a random amount of time within a bound

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

But when I added it to the actual system which needs this kind of utility, I saw results that were very variable

对。线程应用程序是否比串行应用程序运行得更快很大程度上取决于许多因素。特别是,IO 绑定(bind)应用程序的性能不会得到改善,因为它们受到 IO channel 的绑定(bind),因此实际上无法执行并发操作。应用程序需要的处理越多,将其转换为多线程的好处就越大。

Am I just doing it all wrong?

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

您可能还想看看是否可以隔离几个线程中的 IO 操作以及其他线程的处理。就像一个输入线程从文件读取和一个输出线程(或一对)写入数据库或其他东西。因此,多个大小的池可能比使用单个线程池更适合不同类型的任务。

tried using a CompletionService to fetch task results in the order in which they completed

如果您要重试操作,那么使用 CompletionService 正是正确的选择。当作业完成并抛出异常(或返回失败)时,它们可以重新启动并立即放回到线程池中。我不认为您的性能问题会因此而产生。

关于Java ExecutorService - 有时比顺序处理慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18902279/

相关文章:

android - 最大 Activity 数量!

c# - 有没有更有效的方法来计算减法表达式的绝对值

Java:如何使用方法正确返回结果

java - 开关未按预期工作

java错误: Could not find or load main class BinarySearch

ios - 暂停调度队列是否会暂停其目标队列?

c - 子线程中的 malloc 占用太多虚拟内存

multithreading - 如何在 Julia 1.0 中使用多线程?

performance - 使用 Docker 对简单的 Go 服务器造成巨大的性能影响

java - 使用 jxbrowser 的 swing 应用程序上的 "Uncaught ReferenceError: map is not defined"