Fork / Join:最佳线程数

时间:2014-06-16 20:23:55

标签: java multithreading performance concurrency fork-join

任务定义:我需要映射一个非常大的数组。例如,让它成为findMax()函数。因此,任务是尽可能快地完成这项工作(这意味着并行)。

HW:我有8个内核,每个内核都有2个超线程

public static void main(String... args) {
   int maxThreadAmount = Runtime.getRuntime().availableProcessors(); // GET 8
}

解决方案#1:只是将任务运行到N个线程中。其中N应该是一些最优数。

问题#1:下一个是:int optimalThreadAmount = maxThreadAmount - 1

解决方案#2:我想通过Fork / Join框架解决这个问题。如果输入太大,则每个任务分成两个并行子任务。所以我会得到像

这样的东西
                   Find Max 
                   [array]    <---- +1 pending thread
                   /        \
                  /          \
           Find Max        Find Max
          [1/2 array]      [1/2 array]  <-------- +2 pending threads
            /      \          /   \
           /        \        ..   ..
      Find Max      Find Max
     [1/4 array]    [1/4 array]      <-------- +4 four pending threads
       /       \        / \
      /         \      ..  ..
    Find Max    Find Max
    [1/8 array] [1/8 array]  <----------- +8 active threads

问题2: 考虑到使用Fork / Join算法,我们会得到一堆待处理的线程,这将是最佳线程数?

2 个答案:

答案 0 :(得分:3)

最佳线程数应该与您的机器具有的核心数相近。但是,请记住,当您将工作负载分成两个子任务时,一个任务应计算,另一个任务应分叉。这意味着您只能在拆分时创建一个额外的线程。

大多数fork / join算法都伴随着顺序截止。当您达到某个条件(例如,数组以确定大小为1000的最大值)时,您切换到顺序算法(即逐个检查元素)。因此,如果我要猜测最佳情况来计算您的问题,我会说,此时您已经拆分了14次,产生了16个线程,然后切换到顺序算法。这意味着每个核心都有一个线程在运行,因此会保持忙碌状态。 (这个假设假设你的内核有类似超线程的东西,如果不是我会说8个线程)。

此外,我们不建议对您给出的等式(int optimalThreadAmount = maxThreadAmount - 1)进行核心处理,因为这意味着您假设机器不执行任何其他操作并且可以使用所有线程。

我的猜测是,当使用顺序截止时,您的最佳性能将是大约16个线程(当没有其他进程使用您的机器时)。你可以自己测试,这总是最好的方法。您要研究的问题是,当您开始生成大量线程时,每个线程的开销将变得明显。

Ps:使用fork / join的优点是你的代码能够在机器核心数量方面很好地扩展。更多核心意味着更多线程将并行运行。这意味着您的线程调度程序可以使更多线程工作。

修改 那么对于给定数量的内核,我应该使用的最佳截止点是什么?

好吧,我的猜测就是你实现了fork / join算法。您有一个顺序截止(即,一旦我的输入数组的大小为x,就会停止分叉和连接。)

当您知道必须运行算法的系统时,您可以运行基准测试。

对于xy的顺序截止,您运行代码。每次迭代都可以测量应用算法所需的时间。这样做,您将看到哪种配置最适合您。

然后,如果你想要一个快速而肮脏的方法,你可以做到以下几点:

具有p核心的计算机,输入数组的大小为s

Sequential cutoff = s/8

但是,如前所述,我强烈建议不要这样做。

答案 1 :(得分:1)

好的,我想你想把x映射到,比如sqrt(x)。您可以同时获取平方根,并将它们放在相应的数组中。但是,根据sqrt和读/写menory所需的时间,您可能会使用两个线程使您的mem访问权限饱和。确保每个并发作业至少运行μs或者fork / join开销变得太大。