JSR 352 - Java 平台的批处理应用程序使用分区提供并行功能。批处理运行时可以在不同的分区中执行一个步骤,以加快进度。 JSR 352 还引入了 threads
定义:我们可以定义要使用的线程数,例如
<step id="Step1">
<chunk .../>
<partition>
<plan partitions="3" threads="2"/>
</partition>
</chunk>
</step>
然后我就纳闷了:如何给出一个赞赏的分区方案,让每个线程都被占用并保证CPU的平衡?
比如有表A、B、C要做,它们的行分别是10亿、100万、1000。该步骤旨在将这些实体处理为文档,一个实体转到一个文档。文件生成的顺序并不重要。这些表实体的CPU时间分别为1s、2s、5s。线程数为 4。
如果有 3 个分区,每个表类型一个,那么该步骤将采用
1 * 10^9
秒完成,因为:1 * 10^9 * 1s = 1 * 10^9s
,在线程 2 上运行 1 * 10^6 * 2s = 2 * 10^6s
, 在线程 3 1 * 10^3 * 5s = 5 * 10^3s
, 在线程 4 但是,当线程 2 被占用时,线程 3 是空闲的,因为
2 * 10^6s
并且线程 4 从 5 * 10^3s
开始是免费的.所以很明显,这不是一个好的分区计划。我的问题是:
最佳答案
答案...
Is there a better partition plan to complete in the above example?
就在这里。见答案4...
Can I consider : partitions is a queue to consume and threads consume this queue ?
这正是发生的事情!
In general, how many threads can I / should I use ? Is that the same number of the CPU cores ?
这取决于。这个问题有很多角度... 来自 JSR-352 规范 View ,“线程”:
Specifies the maximum number of threads on which to execute the partitions of this step. Note the batch runtime cannot guarantee the requested number of threads are available; it will use as many as it can up to the requested maximum. This is an optional attribute. The default is the number of partitions.
因此,仅从这个角度来看,您应该将此值设置为您想要的任意高(批处理运行时将根据其资源设置真正的限制!)。
从批处理运行时的角度来看(JSR352 实现) :任何体面的实现都将使用线程池来执行分区步骤。因此,如果此类池的大小固定为 N,则无论您设置的线程数有多大,您都不会同时执行超过 N 个分区。
JBeret是JSR352规范的一个实现,被wildfly服务器使用(这是我用过的实现)。在 Wildfly,它的默认线程池设置为最多 10 个线程。该池不仅在分区步骤之间共享,还在批处理作业之间共享。因此,如果您同时运行 2 个作业,您将减少 2 个线程可供使用。除此之外,当你分区时,一个线程扮演协调者的角色,将分区分配给其他线程并等待结果......所以如果你的分区计划说它使用 2 个线程,它实际上会使用 3 个! (两个作为 worker ,一个作为协调员)......所有这些资源(线程)都来自同一个池!
总之,最重要的是:调查您正在使用什么 JSR325 实现并相应地设置它 .
从硬件查看 ,您的 CPU 有线程最大限制。在这个角度下(并且根据经验),将“线程”值设置为等于该值。
从性能 View ,分析你正在做的工作。如果您正在访问多个线程之间的共享资源(如数据库),则可能会产生导致线程阻塞的瓶颈。如果您遇到这种问题,您必须考虑降低“头”值。
总结 ,将“线程”值设置为 CPU 最大线程限制。然后,检查该值是否不会导致阻塞问题;如果是,则降低该值。此外,验证批处理运行时是否已相应配置,它允许您执行任意数量的线程。
In general, how to give an appreciated partition plan so that each thread is occupied and ensure CPU balance ?
避免使用静态分区计划(至少对您而言)。相反,使用分区映射器。分区映射器是一个实现javax.batch.api.partition.PartitionMapper
的类。接口(interface)并允许以编程方式定义分区计划(多少个分区,多少个线程,每个分区的属性)。所以对于你的情况,把你的表(A,B,C)分成N个 block (其中N = 1000)......每个 block 都是一个分区。您应该从类型 C 的分区开始,并在您的实体分区(表)之间进行循环:C0
,B0
,A0
,B1
,A1
, ...,B999
,A999
,A1000
, ...,A999999
...使用此方案,实体 C 将首先完成,留下一个线程打开以解析更多 A 和 B 分区。稍后,B 将完成,留下更多资源来攻击剩余的 A 分区。
希望这有助于...
关于multithreading - 如何在 JSR 352 中定义一个好的分区计划以确保 CPU 平衡?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38675757/