8

我想让下面的代码并行化:

for(int c=0; c<n; ++c) {
    Work(someArray, c);
}

我是这样做的:

#include <thread>
#include <vector>

auto iterationsPerCore = n/numCPU;
std::vector<std::future<void>> futures;

for(auto th = 0; th < numCPU; ++th) {
    for(auto n = th * iterationsPerCore; n < (th+1) * iterationsPerCore; ++n) {
        auto ftr = std::async( std::launch::deferred | std::launch::async,
            [n, iterationsPerCore, someArray]()
            {
                for(auto m = n; m < n + iterationsPerCore; ++m)
                    Work(someArray, m);
            }
        );
        futures.push_back(std::move(ftr));
    }

    for(auto& ftr : futures)
        ftr.wait();
}

// rest of iterations: n%iterationsPerCore
for(auto r = numCPU * iterationsPerCore; r < n; ++r)
    Work(someArray, r);

问题是它在 Intel CPU 上的运行速度仅快50% ,而在 AMD 上则快300%。我在三个 Intel CPU(Nehalem 2core+HT、Sandy Bridge 2core+HT、Ivy Brigde 4core+HT)上运行它。AMD 处理器是 4 核解锁的 Phenom II x2。在 2 核 Intel 处理器上,4 线程运行速度提高 50%。在 4 核上,它在 4 个线程上的运行速度也提高了 50%。我正在使用 VS2012、Windows 7 进行测试。

当我尝试使用 8 个线程时,它比 Intel 上的串行循环慢 8 倍。我想这是由HT引起的。

你怎么看待这件事?这种行为的原因是什么?也许代码不正确?

4

3 回答 3

5

我怀疑虚假分享。当两个变量共享同一个缓存行时,就会发生这种情况。实际上,对它们的所有操作都必须非常昂贵地同步,即使它们不是同时访问的,因为缓存只能根据一定大小的缓存行进行操作,即使您的操作更细粒度。我怀疑 AMD 硬件只是更有弹性,或者有不同的硬件设计来应对这个问题。

要进行测试,请更改代码,使每个核心仅适用于 64 字节的倍数的块。这应该避免任何高速缓存行共享,因为英特尔 CPU 只有一个 64 字节的高速缓存行。

于 2012-12-12T22:19:58.867 回答
2

你也应该对 cpu 缓存感到敬畏。是一篇关于这个主题的好文章。

简短的版本:硬件缓存数据,但如果你在同一个内存(SomeArray)上工作,它必须在 CPU 的缓存之间一直同步,它甚至会导致运行速度比单线程方式慢。

于 2012-12-12T22:15:26.320 回答
2

我会说您需要更改编译器设置以使所有编译的代码最小化分支数量。两种不同的 CPU 样式具有不同的操作前瞻设置。您需要更改编译器优化设置以匹配目标CPU,而不是编译代码的 CPU。

于 2012-12-12T21:10:51.650 回答