【发布时间】:2020-07-29 15:17:57
【问题描述】:
假设如下代码:
#include <thread>
#include <iostream>
#include <vector>
#include <future>
#include <chrono>
#include <cmath>
long long int partialSum(const std::vector<int>& v, int begin, int end) {
long long int sum = 0;
for (int i = begin; i < end; i++) {
sum += (v[i]);
}
return sum;
}
int main() {
std::vector<int> v(10000000, 1);
//2 threads
auto start = std::chrono::high_resolution_clock::now();
std::future<long long int> f1 = std::async(std::launch::async, partialSum, v, 0, 10000000 /2);
std::future<long long int> f2 = std::async(std::launch::async, partialSum, v, 10000000 / 2, 10000000);
volatile long long int a = f1.get() + f2.get();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono:: duration_cast<std::chrono::microseconds>(end - start);
std::cout << "With 2 threads-> " << duration.count() << std::endl;
//1 thread
start = std::chrono::high_resolution_clock::now();
volatile long long int b = partialSum(v, 0, 10000000);
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "With 1 thread-> " << duration.count() << std::endl;
}
以及我机器的输出(VS2019):
With 2 threads-> 35477
With 1 thread-> 7000
请注意,我必须添加 volatile 以避免编译器执行更多优化。
另请注意,我知道std 中有一个accumulate,但我目前正在学习多线程,这是一个 POC。
基本上,我想知道编译器在这里进行了哪种优化,因为与线程版本相比,它的优化非常好。
当我更改partialSum并替换操作(可能是log10)时,线程版本是常规版本的两倍。
编辑: 经过一些建议,我将代码更改为以下代码:
#include <thread>
#include <iostream>
#include <vector>
#include <future>
#include <chrono>
#include <cmath>
long long int partialSum(const std::vector<int>& v, int begin, int end) {
long long int sum = 0;
for (int i = begin; i < end; i++) {
sum += (v[i]);
}
return sum;
}
int main() {
std::vector<int> v(10000000, 1);
//2 threads
auto start = std::chrono::high_resolution_clock::now();
std::future<long long int> f1 = std::async(std::launch::async, partialSum, std::cref(v), 0, 10000000 /2);
std::future<long long int> f2 = std::async(std::launch::async, partialSum, std::cref(v), 10000000 / 2, 10000000);
volatile long long int a = f1.get() + f2.get();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono:: duration_cast<std::chrono::microseconds>(end - start);
std::cout << "With 2 threads-> " << duration.count() << std::endl;
//1 thread
start = std::chrono::high_resolution_clock::now();
f1 = std::async(std::launch::async, partialSum, std::cref(v), 0, 10000000);
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "With 1 thread-> " << duration.count() << std::endl;
}
然后输出:
With 2 threads-> 11835
With 1 thread-> 0
【问题讨论】:
-
切换顺序(第一个线程,第二个线程)......你得到相同或相似的结果吗?
-
@ChrisMM 是的,非常相似
-
可能有两件事:函数实际上很快,开销来自线程启动(我不知道需要多长时间,这也取决于您的操作系统);因为可能 log10 示例需要更长的时间,所以开销不再重要。另一件事可能是线程以某种方式相互干扰缓存行(我不知道这是否可能);但是对于在内存上运行的廉价函数来说,缓存才是王道。
-
@lalala 我仍然认为这里可能在幕后发生了一些事情。这可能是线程创建/控制的开销,但我认为它与缓存无关。
-
@G.Sliepen 如果
sum或i实际上在内存中,编译器应该被解雇
标签: c++ multithreading for-loop optimization