下面的代码取自一个用G++编译的示例。多线程比单线程快2倍。
我在Visual Studio2019中执行它,结果恰恰相反:单线程比多线程快2倍。
#include<thread>
#include<iostream>
#include<chrono>
using namespace std;
using ll = long long;
ll odd, even;
void par(const ll ini, const ll fim)
{
for (auto i = ini; i <= fim; i++)
if (!(i & 1))
even += i;
}
void impar(const ll ini, const ll fim)
{
for (auto i = ini; i <= fim; i++)
if (i & 1)
odd += i;
}
int main()
{
const ll start = 0;
const ll end = 190000000;
/* SINGLE THREADED */
auto start_single = chrono::high_resolution_clock::now();
par(start, end);
impar(start, end);
auto end_single = chrono::high_resolution_clock::now();
auto single_duration = chrono::duration_cast<chrono::microseconds>(end_single - start_single).count();
cout << "SINGLE THREADED\nEven sum: " << even << "\nOdd sum: " << odd << "\nTime: " << single_duration << "ms\n\n\n";
/* END OF SINGLE*/
/* MULTI THREADED */
even = odd = 0;
auto start_multi= chrono::high_resolution_clock::now();
thread t(par, start, end);
thread t2(impar, start, end);
t.join();
t2.join();
auto end_multi = chrono::high_resolution_clock::now();
auto multi_duration = chrono::duration_cast<chrono::microseconds>(end_multi - start_multi).count();
cout << "MULTI THREADED\nEven sum: " << even << "\nOdd sum: " << odd << "\nTime: " << multi_duration << "ms\n";
/*END OF MULTI*/
cout << "\n\nIs multi faster than single? => " << boolalpha << (multi_duration < single_duration) << '\n';
}
但是,如果我对我的函数做一个小的修改,如下所示:
void par(const ll ini, const ll fim)
{
ll temp = 0;
for (auto i = ini; i <= fim; i++)
if (!(i & 1))
temp += i;
even = temp;
}
void impar(const ll ini, const ll fim)
{
ll temp = 0;
for (auto i = ini; i <= fim; i++)
if (i & 1)
odd += i;
odd = temp;
}
多线程的性能更好。我想知道是什么导致了这种行为(在实现方面有哪些可能的差异解释了它)。
此外,我还使用www.onlinegdb.com上的gcc进行了编译,结果与我的计算机中的Visual Studio类似。
你是虚假分享的受害者。
odd
和even
紧挨着驻留,从两个线程访问它们会导致L3高速缓存行争用(也称为虚假共享)。
您可以通过将它们分散64个字节来修复它,以确保它们驻留在不同的缓存行中,例如,如下所示:
alignas(64) ll odd, even;
有了这个改变,我在使用2个线程时获得了很好的加速:
SINGLE THREADED
Even sum: 9025000095000000
Odd sum: 9025000000000000
Time: 825954ms
MULTI THREADED
Even sum: 9025000095000000
Odd sum: 9025000000000000
Time: 532420ms
至于G++的性能--它可能是在执行您手动为您做的优化。MSVC在优化全局变量时会更加小心。