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

时间:2016-07-30 15:51:11

标签: multithreading java-ee jsr352

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

<step id="Step1">
    <chunk .../>
        <partition>
            <plan partitions="3" threads="2"/>
        </partition>
    </chunk>
</step>

然后我感到困惑:如何给出一个受欢迎的分区计划,以便每个线程都被占用并确保CPU平衡?

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

如果有3个分区,每个表类型一个,则该步骤将花费1 * 10^9秒完成,因为:

  • 分区A 将使用1 * 10^9 * 1s = 1 * 10^9s,在线程2上运行
  • 分区B 将使用1 * 10^6 * 2s = 2 * 10^6s,在线程3上运行
  • 分区C 将使用1 * 10^3 * 5s = 5 * 10^3s,在第4个线程上运行

然而,当线程2被占用时,线程3是空闲的,因为2 * 10^6s并且线程4从5 * 10^3s开始是空闲的。很明显,这不是一个好的分区计划。

我的问题是:

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

1 个答案:

答案 0 :(得分:2)

...答案

  

在上面的示例中是否有更好的分区计划要完成?

是的,有。见答案4 ......

  

我可以考虑:分区是要使用的队列,线程是否使用此队列?

这就是确切发生的事情!

  

一般情况下,我可以/应该使用多少个线程?这是相同数量的CPU核心吗?

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

  
    

指定执行分区的最大线程数     这一步请注意,批处理运行时无法保证所请求的线程数可用;它将尽可能多地使用所需的最大值。这是一个可选属性。默认值是分区数。

  

因此,仅基于此视角,您应该根据需要将此值设置为高(批处理运行时将根据其资源设置实际限制!)。

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

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

无论如何,重要的是:调查您使用的JSR325的实现并相应地设置

从硬件视图,您的CPU具有线程最大限制。在此视角下(以及经验法则),将“线程”值设置为等于此值。

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

在摘要中,将“threads”值设置为CPU最大线程限制。然后,检查该值是否不会导致阻塞问题;如果是这样,减少价值。另外,验证它是否相应地配置了批处理运行时,它允许您根据需要执行任意数量的线程。

  

一般来说,如何给出一个受欢迎的分区计划,以便每个线程都被占用并确保CPU平衡?

避免使用静态分区计划(至少对于您而言)。而是使用分区映射器。 Partition Mapper是一个实现javax.batch.api.partition.PartitionMapper接口的类,允许以编程方式定义分区计划(分区数量,线程数,每个分区的属性)。所以对于你的情况,拿你的表(A,B,C)并将它们分成N个块(其中N = 1000)......每个块都是一个分区。您应该从C类型的分区开始,并在您的实体分区(表)之间进行循环:C0B0A0B1A1 ,...,B999A999A1000,...,A999999 ...使用此方案,实体C将首先完成,将一个线程打开解决更多A和B分区。之后,B将完成,留下更多资源来攻击剩余的A分区。

希望这有帮助...