多线程应用程序根据线程数

时间:2016-03-17 21:21:02

标签: java multithreading cyclicbarrier

我正在为N-Body问题实现Barnes-Hut算法的多线程解决方案。

Main class执行以下操作

public void runSimulation() {
        for(int i = 0; i < numWorkers; i++) {
            new Thread(new Worker(i, this, gnumBodies, numSteps)).start();
        }
        try {
            startBarrier.await();
            stopBarrier.await();
        } catch (Exception e) {e.printStackTrace();}
}

bh.stop-和bh.startBarrier是CyclicBarriers,将start-和stopTime设置为System.nanoTime();到达时(屏障行动)。

工人运行方法:

public void run() {
    try {
        bh.startBarrier.await();

        for(int j = 0; j < numSteps; j++) {
            for(int i = wid; i < gnumBodies; i += bh.numWorkers) {
                bh.addForce(i);
                bh.moveBody(i);
            }
            bh.barrier.await();
        }
        bh.stopBarrier.await();
    } catch (Exception e) {e.printStackTrace();}
}

addForce(i)遍历树并进行一些计算。它不会影响任何共享变量,因此不使用任何同步。 O(NlogN)。

moveBody(i)对一个元素进行计算,不使用同步。 O(N)。

当达到bh.barrier时,会建立一个包含所有实体的树(屏障动作)。

现在问题。运行时随着使用的线程数线性增加。 gnumBodies的运行时间= 240,numSteps = 85000和四个核心:

  • 1个帖子= 0.763
  • 2个主题= 0.952
  • 3个主题= 1.261
  • 4个主题= 1.563

为什么运行时不会随着使用的线程数而减少?

编辑:添加硬件信息

5 个答案:

答案 0 :(得分:1)

你在运行什么硬件?运行多个线程有其开销,因此在将任务拆分为小的子任务时可能不值得。

另外,尝试使用ExecutorService而不是线程。这样您就可以使用线程池而不是为每个任务创建实际线程。拥有更多可以处理硬件的线程是没有用的。

在我看来,每个线程都会做同样的工作。情况可能如此吗?在创建工作者时,除了i之外,每次都使用相同的参数。

答案 1 :(得分:0)

多线程不会提高执行速度,除非您还有多个CPU核心。

线程进行数学计算并可以全速运行

如果您只有一个CPU核心,如果您在一个线程或多个线程中运行计算,则它们都是相同的。在多个线程中运行不会带来任何性能优势,但会带来线程切换的开销,因此实际上总体性能会稍差一些。

如果您有多个可用的CPU核心,则线程可以物理并行运行,最多可达核心数。这意味着4-8个线程可以在当今的桌面硬件上运行良好。

线程等待IO并被暂停

如果您不进行数学计算,但做一些涉及网络,文件或数据库等慢速I / O的操作,则线程是有意义的。当一个线程等待IO时,不是占用程序的运行,而是另一个线程可以使用相同的CPU核心。这就是为什么Web服务器和数据库解决方案可以使用比CPU核心更多的线程的原因。

避免不必要的同步

然而,您的测量显示同步错误。 我想你应该从线程代码中删除所有xxbarrier.await()。 我不确定xxBarriers与系统纳米级的目标是什么,但任何不必要的同步化都很容易导致性能下降。您没有计算,而是等待xxxBarriers。

答案 2 :(得分:0)

您的员工独立完成同样的工作numWorker次。 唯一的共享对象是您的CyclicBarrier。 await()等待所有奇偶校验在此障碍上等待。随着工人数量的增加,它会花费更多时间在await()

答案 3 :(得分:0)

如果您有多个内核或者超线程可用,那么运行多个线程将获得底层硬件的好处。

如果只存在一个核心,如果您的应用程序涉及至少一个非CPU密集型工作(如与人的交互),则多线程可以提供“感知”的好处。与现代CPU相比,人类非常缓慢。因此,如果您的应用程序需要从人类获取多个输入并处理它们,那么在两个线程中分开输入和计算是有意义的。到人类将提供输入时,部分计算可以在另一个线程中完成。从而整体改善了时间。

如果应用程序必须进行计算并且不存在硬件中的多线程支持,则最好使用单线程。您的“计算”已经在管道中背靠背排列,CPU已经以(几乎)最大速度运行。多线程需要上下文切换时间,这将增加进行计算所需的时间。

答案 4 :(得分:0)

当我运行具有更多主体的应用程序更少的步骤时,应用程序按预期缩放。所以问题可能就是屏障的开销!