我正在开发一种微服务,其操作流程如下:
请求执行一些任务。经过一些预处理后,我知道我需要执行一些任务,比方说10。现在,这些任务彼此独立,因此可以并行执行。每个任务都有一些处理步骤和一些外部API调用。在完成所有任务后,需要返回合并的结果。
这是一个请求,因此很明显,此微服务也可以并行获取许多这样的请求。
在这里,API调用是最耗时的操作,相对而言,其他工作执行的时间要短得多。因此,我想以一种可以并行执行许多任务的方式进行设计,因为对于API调用,大多数任务会被阻塞。
我看到的一个简单解决方案是使用ExecutorService使用线程池,但这似乎不是理想的解决方案,因为假设我创建了一个包含32个线程的线程池,并且得到60个任务。因此,即使这32个任务因api调用而被阻塞并且不占用太多CPU时间,一次也只能执行32个。
在不破坏单个任务的情况下是否可以实现?
答案 0 :(得分:3)
最佳线程数取决于服务器具有的内核数以及I / O工作负载所花费的时间。请参见http://baddotrobot.com/blog/2013/06/01/optimum-number-of-threads/进行计算。
简而言之,它指出:threads = number of cores * (1 + wait time / service time)
时间必须来自您的观察和测量。
对于其余部分,您可以使用注释中提到的CompletableFuture
,也可以使用Executors
类:Executors.newFixedThreadPool(<num of threads>);
答案 1 :(得分:1)
一种解决方法是确保线程池始终至少包含n
个处于可运行状态的线程(其中n
通常等于CPU内核的数量)。这意味着您需要管理阻塞,并且只要线程开始阻塞,就将线程添加到池中,并在线程退出阻塞后再次将其删除。
Java的ForkJoinPool.ManagedBlocker
是使用parallel streams时类似问题的解决方案的一部分。
Scala通过使用ExecutionContext
时使用的futures来概括和简化这一方面。
答案 2 :(得分:0)
您将必须进行一些基准测试,以找出最适合您的设置的方法。您可能想研究使用ThreadPoolExecutor
,它可以根据池中可用的线程数来增加和减少线程数。您可以在基准测试中调整一些参数,即corePoolSize
和maximumPoolSize
。
答案 3 :(得分:0)
LEFT()
具有一些控制参数(核心池大小(<32),最大池大小(60)),允许60个线程用于32个内核当28个活动线程被阻止时,它将很好地工作。
您描述的星座通常会使用任务队列,但是您要求的CPU使用率最高。尽管在微服务方面,其他方面(而不是核心)也发挥了作用。