【问题标题】:Java multiple threads give very small perfomance gainJava 多线程提供非常小的性能增益
【发布时间】:2017-04-26 12:55:21
【问题描述】:

我想学习并行编程以加速算法并选择了 Java。
我写了两个函数来对数组中的long 整数求和 - 一个是简单的遍历数组,第二个 - 将数组划分为多个部分并在分离的线程中对部分求和。

我预计使用两个线程将速度提高大约 2 倍是合乎逻辑的。然而,我所得到的只是 24% 的加速。此外,使用更多线程,我没有比两个线程得到任何改进(可能少于 1%)。我知道应该有线程创建/加入开销,但我想它不应该那么大。

您能否解释一下,我缺少什么或代码中的错误在哪里? 这是代码:

import java.util.concurrent.ThreadLocalRandom;


public class ParallelTest {


public static long sum1 (long[] num, int a, int b) {
    long r = 0;
    while (a < b) {
        r += num[a];
        ++a;
    }
    return r;
}

public static class SumThread extends Thread {
    private long num[];
    private long r;
    private int a, b;

    public SumThread (long[] num, int a, int b) {
        super();
        this.num = num;
        this.a = a;
        this.b = b;
    }

    @Override
    public void run () {
        r = ParallelTest.sum1(num, a, b);
    }

    public long getSum () {
        return r;
    }
}


public static long sum2 (long[] num, int a, int b, int threadCnt) throws InterruptedException {
    SumThread[] th = new SumThread[threadCnt];
    int i = 0, c = (b - a + threadCnt - 1) / threadCnt;

    for (;;) {
        int a2 = a + c;
        if (a2 > b) {
            a2 = b;
        }
        th[i] = new SumThread(num, a, a2);
        th[i].start();
        if (a2 == b) {
            break;
        }
        a = a2;
        ++i;
    }

    for (i = 0; i < threadCnt; ++i) {
        th[i].join();
    }
    long r = 0;
    for (i = 0; i < threadCnt; ++i) {
        r += th[i].getSum();
    }
    return r;
}

public static void main(String[] args) throws InterruptedException {
    final int N = 230000000;
    long[] num = new long[N];

    for (int i = 0; i < N; ++i) {
        num[i] = ThreadLocalRandom.current().nextLong(1, 9999);
    }

    // System.out.println(Runtime.getRuntime().availableProcessors());

    long timestamp = System.nanoTime();
    System.out.println(sum1(num, 0, num.length));
    System.out.println(System.nanoTime() - timestamp);

    for (int n = 2; n <= 4; ++n) {
        timestamp = System.nanoTime();
        System.out.println(sum2(num, 0, num.length, n));
        System.out.println(System.nanoTime() - timestamp);
    }


}
}

编辑:我有 4 个内核(8 个线程)的 i7 处理器。 代码给出的输出是:

1149914787860
175689196
1149914787860
149224086
1149914787860
147709988
1149914787860
138243999

【问题讨论】:

    标签: java multithreading parallel-processing


    【解决方案1】:

    该程序的主内存带宽可能仅限于两个线程,因为它是一个小循环,它获取数据的速度几乎与 ram 向处理器提供数据的速度一样快。

    【讨论】:

    • 也就是说,如果我在循环中有更多的 CPU 密集型任务,那么我会通过更多线程获得更好的性能增益?
    【解决方案2】:

    我可以想到一些可能导致您无法获得预期加速的原因。

    1. 线程创建开销很大。线程start() 是一项昂贵的操作,它需要多个系统调用来分配线程堆栈及其“红区”,然后创建本机线程。

    2. N 个线程不会同时启动。这意味着完成计算的并行部分的时间将大约是最后一个线程的结束时间 - 第一次的开始时间。这将比一个线程完成其部分工作所需的时间更长。 (按线程创建时间的N-1倍...)

    3. N 个线程(基本上)对阵列的 N 个不相交部分进行串行扫描。这是内存带宽密集型的,并且您扫描的方式意味着内存缓存将无效。因此,性能很可能受到系统主内存硬件的速度和带宽的限制。

    【讨论】:

      猜你喜欢
      • 2016-12-19
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多