C++ 为什么并行化版本比单线程版本慢。虚假分享?
下面是代码的两个版本:C++ 为什么并行化版本比单线程版本慢。虚假分享?,c++,multithreading,parallel-processing,process,C++,Multithreading,Parallel Processing,Process,下面是代码的两个版本: class VectorCount { private: char *arr;int size;unsigned long long count; public: VectorCount(char *arr, unsigned int size, unsigned long long count) : arr(arr), size(size), count(count) {}
class VectorCount {
private:
char *arr;int
size;unsigned long long count;
public:
VectorCount(char *arr, unsigned int size, unsigned long long count) : arr(arr), size(size), count(count) {}
void add() {
while(count--) {
for (int i = 0; i < size; i++) {
arr[i]++;
}
}
}
};
// Single-thread version of the code
void main_st() {
// initizalize array
char arr[10];
// create object
VectorCount v(arr, 10, 100000000);
// run add
v.add();
}
// Parallelized version of the code
void main_mt() {
// initialize array
char arrA[10];
char arrB[10];
// create objects
VectorCount v1(arrA, 10, 50000000);
VectorCount v2(arrB, 10, 50000000);
// create threads
thread t1, t2;
t1.create_thread(v1, v1.add);
t2.create_thread(v2, v2.add);
// join threads
t1.join();
t2.join();
// Code to do the final sum of the two VectorCount objects to get the same
// result as the single-threaded version (assume negligible overhead here)
}
类向量计数{
私人:
字符*arr;int
大小;无符号长计数;
公众:
向量计数(char*arr,unsigned int size,unsigned long long count):arr(arr),size(size),count(count){
void add(){
而(计数--){
对于(int i=0;i
假设程序创建了一个数组大小为10、计数为1亿的VectorCount对象实例。单线程版本需要5秒来完成总和。并行化版本使用两个线程,每个线程分别持有一个数组大小为10的VectorCount实例,因此每个VectorCount实例的计数仅为5000万,因为每个线程完成了一半的工作。并行化版本需要8秒钟才能完成。为什么会慢一些?我想这是因为虚假的分享。但我不确定。缓存大小为64字节
我们能让并行版本运行得更快吗?我正在考虑更改向量计数数组大小。但是,使用2个线程时,多大的大小会使并行化版本运行得更快呢?既然缓存大小是64字节,int是4字节,那么size=16能解决这种情况下的错误共享吗?(4 x 16=64)
谢谢您的帮助。您的代码只做了很少的工作,只要有足够的上下文,优化人员就可以将您的代码转换为基本的内容(假设与您的情况一样,
count
可以被size
整除):
使它更类似于您的单线程版本,并且Optimizer能够执行其神奇功能,而并行版本的速度要快得多:。如果您查看第一个版本的汇编代码,您会注意到其中提到了50000000
,但没有提到100000000
,在第二个版本中,您会注意到50000000
也没有,因为两个版本都没有优化
请注意,它仍然比单线程版本慢,但由于单线程版本只需要约100ns的时间,因此创建和连接两个线程的开销可能比从并行性中节省的开销要大
在我使用visual studio的机器上,单线程版本的代码需要85毫秒,并行版本的代码需要45毫秒(visual studio无法完全删除代码)
阻塞Optimizer会在GCC上给出更相似的结果:最好有一个可复制的示例。更好的利用甚至还有一些可能性:首先,它可能是两个线程调度在同一个内核上,这比单线程慢。第二,每次在不同的内核上安排两个线程版本,这会导致旧内核中的刷新缓存和当前内核中的未命中缓存。您的代码做得很少,并且可能会被编译器优化,创建线程可能比您的代码可能归结为的10个赋值花费更长的时间,如果您的代码没有得到优化,那么任何性能度量都是没有意义的,即
t1
和t2
std::thread
s?我似乎找不到任何名为create\u thread
的成员函数。
for (int i = 0; i < size; i++) {
arr[i] = count / size;
}
std::thread t1([] {
char arrA[10]{0};
VectorCount v1(arrA, 10, 50'000'000);
v1.add();
});
std::thread t2([] {
char arrA[10]{0};
VectorCount v1(arrA, 10, 50'000'000);
v1.add();
}
);