我正在尝试并行化代码。但是我注意到C ++中有一个奇怪的行为。我将问题简化为以下内容: 我有一个巨大的数组(100M字节)。当我在单线程中对此数据写入随机数据时,它比并行运行(例如10核)要快得多。我假设通过考虑大于1GB / s的RAM速度,在RAM上并行写入应该没有任何问题。代码是这样的:
#include <iostream>
#include <type_traits>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <chrono>
#include <thread>
using namespace std;
uint8_t g[16]{1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 10, 1};
uint8_t** data = new uint8_t*[1000];
void test() {
for (int i = 1; i < 100000000; i++) {
int row = rand() % 1000;
int col = rand() % 10000000;
memcpy(&data[row][col], &g[0], 16);
memcpy(&data[row][col + 16], &g[0], 16);
}
}
#define TH 1
int main() {
for (int i = 0; i < 1000; i++) {
data[i] = new uint8_t[10000000];
}
std::chrono::time_point<std::chrono::high_resolution_clock> m_beg = std::chrono::high_resolution_clock::now();
std::thread* workers = new std::thread[TH];
for (int i = 0; i < TH; i++) {
workers[i] = std::thread(&test);
}
for (int i = 0; i < TH; i++) {
workers[i].join();
}
double t = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_beg).count();
cout << t << endl;
}
我与设置进行了比较:
1-TH = 1,测试循环计数器= 100M
2-TH = 10,测试循环计数器= 10M
其结果如下:
1-10秒
2-72秒
有人知道原因是什么吗?
答案 0 :(得分:4)
您的所有线程都以随机方式访问相同的数据。
每次一个线程向某个位置写入内容时,所有具有此值的高速缓存行都会失效,必须对其进行更新。而且这种情况一直发生在您所有的线程上,从而使您所有缓存中的数据一次都失效。
这与锁定无关,而是与来自具有相同数据的其他内核的缓存行必须无效这一事实有关。这是有代价的。
想象一下,在一堵小墙上有1000000颗螺钉。你有十个人,有十把螺丝刀。它们都会互相妨碍,因为如果它们要在同一位置的两个螺钉上工作,则它们可以高效地工作。这里也有点像这样,但是具有更多的层次结构。