哪个执行人员服务最适合阻止IO任务
让我们想象,我们有n个独立的阻止IO任务,例如将rest通用到另一台服务器的任务。然后所有答案我们都需要组合。每个任务都可以处理10秒以上。
我们可以顺序处理它,并在末尾花费〜n*10秒:
task1ans task1 = service1.dosomething(); task2ans task2 = service2.dosomething() ... 返回结果;
另一个策略是使用完整的future以并行方式处理它,并在所有任务上花费了〜10秒:
完整的future< task1ans> task1cs = ploctableFuture.supplyAsync((() - > service1.dosomething(),bestExeCutor); 完整的future< task2ans> task2cs = ploteableFuture.supplyAsync(() - > service2.dosomething(),bestExeCutor); 返回完整的future.allof(task1cs,task2cs) 。 ... //将任务1,任务2组合到结果对象中 返回结果; })。加入();
第二种方法具有好处,但我不明白哪种类型的线程池是适合此类任务的最好的:
ExecutorService bestExecutor = Executors.newFixedThreadPool(30) /// or Executors.newCachedThreadPool() or Executors.newWorkStealingPool()
我的问题是哪种方法是执行人员服务最适合过程N-并行阻止IO任务。
Let's imagine that we have n independent blocking IO tasks e.g. tasks for rest-call to another server. Then all answer we need to combine. Every task can be processing over 10 second.
We can process it sequentially and spent ~n*10 second at the end:
Task1Ans task1 = service1.doSomething(); Task2Ans task2 = service2.doSomething() ... return result;
Another strategy is to process it in parallel manner using CompletableFuture and spent ~ 10 second on all task:
CompletableFuture<Task1Ans> task1Cs = CompletableFuture.supplyAsync(() -> service1.doSomething(), bestExecutor); CompletableFuture<Task2Ans> task2Cs = CompletableFuture.supplyAsync(() -> service2.doSomething(), bestExecutor); return CompletableFuture.allOf(task1Cs, task2Cs) .thenApply(nothing -> { ... // combine task1, task2 into result object return result; }).join();
The second approach has benefits, but I can't understand which type of thread pool is the best for this kind of task:
ExecutorService bestExecutor = Executors.newFixedThreadPool(30) /// or Executors.newCachedThreadPool() or Executors.newWorkStealingPool()
My question is which ExecutorService is best for process n-parallel blocking IO tasks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在CPU绑定的任务上,您不会通过比CPU内核更多的线程获得其他性能。因此,在这种情况下,8 Core / 8线程CPU仅需8个线程即可最大程度地提高性能,并通过更多信息来失去性能。与CPU内核相比,IO任务通常可以通过使用大量线程来获得性能,因为CPU时间可以在等待IO时进行其他事情。但是,即使每个线程的CPU开销较低,每个线程都会进食内存,并且会限制缩放,并会产生缓存/上下文开关。
鉴于您的任务是io限制的,并且您没有提供任何其他约束,您应该应该可能只是为您的每个IO任务运行不同的线程。您可以使用固定或缓存的线程池来实现这一目标。
如果您的IO任务的数量很大(千+),则应限制线程池的最大尺寸,因为您可以拥有太多的线程。
如果您的任务是CPU绑定的,则应再次将线程池限制为更小的尺寸。 可以通过以下方式动态获取
可以通过使用:同样,就像您的CPU具有缩放限制一样,您的IO设备通常也具有缩放限制,也 。您不应该超过该限制,但是如果不衡量,很难说限制在哪里。
On completely CPU bound tasks you do not get additional performances by going with more threads than CPU cores. So in this scenario, 8 core / 8 thread CPU needs only 8 thread to maximize performances, and loses performance by going with more. IO tasks usually do gain performances by going with larger number of threads than CPU cores, as CPU time is available to do other stuff while waiting for IO. But even when CPU overhead of each thread is low there are limits to scaling as each thread eats into memory, and incurs caching/context switches..
Given that your task is IO limited, and you didn't provide any other constraints, you should probably just run different thread for each of your IO tasks. You can achieve this by either using fixed or cached thread pool.
If the number of your IO tasks is very large (thousands+), you should limit the maximum size of your thread pool, as you can have such thing as too many of threads.
If your task are CPU bound, you should again limit thread pool to even smaller size. Number of cores can be dynamically fetched by using:
Also, just as your CPU has scaling limit, your IO device usually has a scaling limit too. You should not exceed that limit, but without measuring it is hard to say where limit is.
Project Loom
您的情况适合使用为Java的未来版本提出的新功能: and 结构化的并发。这些是 project loom 。
当今的Java线程被映射到主机操作系统线程上。当Java代码块时,主机线程块。主机操作系统坐着空闲,等待执行恢复。主机操作系统线程是重量级的,就CPU和内存而言。因此,这个空转不是最佳的。
相比之下,项目织机中的虚拟线程被映射到主机OS线程上。当在虚拟线程块中代码时,该任务是“停放”的,请放置以允许另一个虚拟线程的任务在某些执行时间。虚拟线程的这种停车位在JVM内进行管理,因此在CPU和内存中,它都非常优化,非常快,非常有效。结果,在通用硬件上运行的Java应用程序一次可以支持数千个虚拟线程。
executorService
是Autoclosable
在Loom中。因此,我们可以使用try-with-resources在try(executorService es = executors.newvirtualThreadPertasKexecutor())中包含您的整个任务。完成后,控制流程从try-with-resources块中退出,您知道自己的任务已完成。访问
未来
对您提交的每个任务返回的对象。无需完整的future
。现在在Java 19和20中预览和孵育织机功能。虚拟线程功能是计划在Java 21 <21 < /a>。
有关更多信息,请参阅与项目LOOM团队成员的几篇文章,演讲和访谈。其中包括罗恩·波特勒(Ron Pressler)和艾伦·贝特曼(Alan Bateman)。并查看jepCafé的相关插曲。
Project Loom
Your situation is suited to using the new features being proposed for future versions of Java: virtual threads and structured concurrency. These are part of Project Loom.
Today’s Java threads are mapped one-to-one onto host operating system threads. When Java code blocks, the host thread blocks. The host OS threads sits idle, waiting for execution to resume. Host OS threads are heavyweight, costly in terms of both CPU and memory. So this idling is not optimal.
In contrast, virtual threads in Project Loom are mapped many to one onto the host OS thread. When code in a virtual thread blocks, that task is “parked”, set aside to allow another virtual thread’s task some execution time. This parking of virtual threads is managed within the JVM, so it is highly optimized, very fast, very efficient both in CPU and in memory. As a result, Java apps running on common hardware can support thousands, even millions, of virtual threads at a time.
The
ExecutorService
isAutoCloseable
in Loom. So we can use try-with-resources to contain your entire batch of tasks in atry ( ExecutorService es = Executors.newVirtualThreadPerTaskExecutor() ) { … submit tasks … }
. Once completed, the flow of control exits from the try-with-resources block, and you know your tasks are done. Access theFuture
object returned for each task you submitted. No need forCompletableFuture
.Loom features are now being previewed and incubated in Java 19 and 20. The virtual threads feature is planned for release in Java 21.
For more info, see the several articles, presentations, and interviews with members of the Project Loom team. These include Ron Pressler and Alan Bateman. And see relevant episodes of JEP Café.
如果我正确理解您的问题,则无论选择
executorService
,都更重要的是如何调用executorService
。例如
,现在在这里,
InvokeAll(..)
将阻止直到完成内部提供的所有任务。因此,我觉得选择任何执行人员服务&amp;调用
InvokeAll(..)
将适合您的要求。另外,请查看此 se问题讨论新Java 8 &amp;
InvoKeall
。If I understand your question properly, for above behaviour, irrespective of selection of
executorService
, it is more important how you are calling yourexecutorService
.E.g.
Now here,
invokeAll(..)
will block until all supplied tasks inside are completed.So I feel selecting any ExecutorService & calling
invokeAll(..)
will be suitable for your requirement.Also please have a look at this SE Question which discusses new Java 8 introduction of ExecutorCompletionService &
invokeAll
.我找到了此类任务的最佳解决方案。要找到解决方案的目的是查看执行者的实现。newcachedThreadPool()或opecutors.newfixedthreadpool(30)
我的决定是直接实例化ThreadPoolPoolExecutor,并设置可以由线程池创建的线程的上限。并在未使用的线程后设置超时
I found the optimal solution for this kind of task. All I nead to find the solution is to look at implementation of Executors.newCachedThreadPool() or Executors.newFixedThreadPool(30)
My decision is to instantiate ThreadPoolExecutor directly and set upper bound of threads that can be created by thread pool. And set timeout after unused threads can be terminated