在 JSR 352 中如何定义一个好的分区计划来保证 CPU 平衡?

Min*_*ang 5 multithreading jsr352 jakarta-ee

JSR 352 - Java 平台的批处理应用程序使用分区提供并行功能。批处理运行时可以在不同的分区中执行一个步骤以加快进度。JSR 352 还引入了threads定义:我们可以定义要使用的线程数,例如

<step id="Step1">
    <chunk .../>
        <partition>
            <plan partitions="3" threads="2"/>
        </partition>
    </chunk>
</step>
Run Code Online (Sandbox Code Playgroud)

然后我就很困惑:如何给出一个赞赏的分区计划,使每个线程都被占用并确保CPU平衡?

例如,有表A、B、C要做,它们的行分别是10亿、100万、1000。该步骤旨在将这些实体处理为文档,一个实体转到一个文档。文件制作的顺序并不重要。这些表实体的CPU时间分别为1s、2s、5s。线程数为 4。

如果有 3 个分区,每个表类型一个,那么该步骤将需要1 * 10^9几秒钟才能完成,因为:

  • 分区 A1 * 10^9 * 1s = 1 * 10^9s在线程 2 上运行
  • 分区 B1 * 10^6 * 2s = 2 * 10^6s在线程 3 上运行
  • 分区 C1 * 10^3 * 5s = 5 * 10^3s在线程 4 上运行

然而,当线程 2 被占用时,线程 3 是空闲的,2 * 10^6s而线程 4 是空闲的5 * 10^3s。所以很明显,这不是一个好的分区方案。

我的问题是:

  • 在上面的例子中是否有更好的分区计划来完成?
  • 我可以考虑:partitions是一个要消耗的队列,而线程消耗这个队列吗?
  • 一般来说,我可以/应该使用多少个线程?这是相同数量的 CPU 内核吗?
  • 一般来说,如何给出一个受欢迎的分区计划,以便每个线程都被占用并确保 CPU 平衡?

Car*_*Way 3

答案...

上面的例子有没有更好的分区方案可以完成呢?

就在这里。参见答案4...

我可以考虑:分区是一个要消耗的队列,线程消耗这个队列吗?

这正是发生的事情!

一般来说,我可以/应该使用多少个线程?CPU 核心数相同吗?

这取决于。这个问题有很多观点...... 从 JSR-352 规范视图来看,“线程”:

指定执行此步骤的分区的最大线程数。请注意,批处理运行时不能保证请求的线程数可用;它将使用尽可能多的数量,直至达到请求的最大值。这是一个可选属性。默认为分区数。

因此,仅从这个角度来看,您应该将该值设置为您想要的尽可能高的值(批处理运行时将根据其资源设置真正的限制!)。

从批处理运行时角度(JSR352 实现):任何合适的实现都将使用线程池来执行分区步骤。因此,如果此类池的大小固定为 N,则无论您将线程数设置多大,都不会同时执行超过 N 个分区。

JBeret是JSR352规范的实现,由wildfly服务器使用(这是我使用的实现)。在 Wildfly,它的默认线程池设置为最多 10 个线程。该池不仅在分区步骤之间共享,还在批处理作业之间共享。因此,如果您同时运行 2 个作业,则将减少 2 个线程可供使用。除此之外,当您进行分区时,一个线程将扮演协调器的角色,将分区分配给其他线程并等待结果……因此,如果您的分区计划说它使用 2 个线程,那么实际上它会使用 3 个线程!(两个作为工作人员,一个作为协调员)...所有这些资源(线程)都来自同一个池!

无论如何,最重要的是:调查您正在使用 JSR325 的哪种实现并进行相应的设置

从硬件角度来看,你的CPU有一个线程最大限制。在此视角下(并且根据经验),将“线程”值设置为等于该值。

从绩效视图中,分析您正在做的工作。如果您在多个线程之间访问共享资源(例如数据库),则可能会产生导致线程阻塞的瓶颈。如果您遇到此类问题,您必须考虑降低“theads”值。

在摘要中,将“线程”值设置为与 CPU 最大线程限制一样高。然后,检查该值是否不会导致阻塞问题;如果是,则减少该值。另外,请验证批处理运行时是否已相应配置,并且它允许您执行所需数量的线程。

一般来说,如何给出一个合适的分区计划,使得每个线程都被占用并保证CPU平衡?

避免使用静态分区计划(至少对于您的情况)。相反,请使用分区映射器。分区映射器是一个实现javax.batch.api.partition.PartitionMapper接口并允许以编程方式定义分区计划(多少个分区、多少个线程、每个分区的属性)的类。因此,对于您的情况,将表(A、B、C)分成 N 个块(其中 N = 1000)...每个块将是一个分区。您应该从类型 C 的分区开始,并在实体分区(表)之间进行循环:C0, B0, A0, B1, A1, ..., B999, A999, A1000, ..., A999999... 使用此方案,实体 C 将首先完成,保留一个线程打开以解决更多 A 和 B 分区。稍后,B 将完成,留下更多资源来攻击剩余的 A 分区。

希望这有帮助...