这是我在这里的第一篇文章,虽然我确实定期访问该网站,并在此处找到了许多有价值的信息。
我有一个令人尴尬的并行算法,我希望通过多线程可以显示出很好的性能提升。
这是我第一次使用多线程,经过大量的阅读和评论。
我正在使用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());
}
我发布整个代码没有问题 - 但我想我会从这些关键部分开始。
提前获得任何洞察力。
答案 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带宽,让你非常接近最高速度。