为什么多线程无法改善这种令人尴尬的并行算法的性能?

时间:2016-01-07 01:13:06

标签: c++ multithreading performance

这是我在这里的第一篇文章,虽然我确实定期访问该网站,并在此处找到了许多有价值的信息。

我有一个令人尴尬的并行算法,我希望通过多线程可以显示出很好的性能提升。

这是我第一次使用多线程,经过大量的阅读和评论。

我正在使用VS 2012进行C ++工作,而我的Windows 7笔记本电脑配备了一个具有四核和大量内存的i7处理器。

基础工作分解为这个伪代码

for (int i = 0; i<iMax; i++){
    for (int j = 0; j<jMax; j++){
        T[j] += E[j][i] * SF;
    }
}

T,E和SF是花车。

该实现使用来自here的(修改的)线程池。

从此函数构建并添加一组线程池任务

void doWork(float *T, float *E, float SF, int numNodes)
{
    // Critical for performance that these loops vectorize.....
    for (int nodeCounter = 0; nodeCounter < numNodes; nodeCounter++){
        T[nodeCounter] += E[nodeCounter] * SF;
    }
};

使用此构造,

tp.enqueue(std::bind(&doWork, timeStepDisplacements.T1, T1MODE, T1MPF, numNodes));

在我的测试中,numNodes为1,000,000,我为50个外部循环中的每一个调用此例程3次(使用不同的数组)。我还有另一个循环(100),所以我的测试代码生成 15,000 这些任务,每个任务执行1,000,000次乘法。

编辑:将外圈数量修正为100,任务数量从7,500增加到15,000

当我使用8个,16个或更多线程设置我的线程池时,性能仅略高于串行代码 - 比如8.8秒v的9.3。

所以我的问题是为什么性能提升如此之小?

注意 - 如果使用不同的任务例程(下面的work_proc),相同的线程池设置会显示出很大的性能提升。

void work_proc()
{
    int i = 555;
    std::random_device rd;
    std::mt19937 rng(rd());

    // build a vector of random numbers
    std::vector<int> data;
    data.reserve(100000);
    std::generate_n(std::back_inserter(data), data.capacity(), [&](){ return rng(); });
    std::sort(data.begin(), data.end());
}

我发布整个代码没有问题 - 但我想我会从这些关键部分开始。

提前获得任何洞察力。

1 个答案:

答案 0 :(得分:4)

您可能已经掩盖了一些重要的位,但如果您的伪代码是准确的,那么看起来瓶颈就是内存访问。

单个核心可以足够快地添加数字以使您的DRAM得到充分利用,因此通过拆分工作可以获得不太高的性能。

编辑:如果您知道您的DRAM类型和I / O时钟速率,您可以计算您的DRAM传输速率。这是关于它的速度有多快?

例如:9.3秒内的15000 * 1000000浮点数为6.4 GB / s。如果您正在写相同的金额,则为12.8 GB / s,这是您在评论中使用的DDR3-1600的最高费率...

所以这肯定是你的问题。

请注意,您不应该需要来写相同数量的内容,因此如果您重新构建算法以使其更加缓存友好,那么您可以将它的速度提高一倍。

如果你有每个工人做4 Es,比如:

T[nodeCounter] += (E1[nodeCounter] + E2[nodeCounter] + E3[nodeCounter] + E4[nodeCounter])*SF

然后这会显着降低你的T带宽,让你非常接近最高速度。

相关问题