c++ - C++ 多线程性能比单线程代码慢
问题描述
我正在学习在 c++ 中使用线程
我用整数创建了一个很长的向量并设置了另一个整数 x。我想计算该整数与向量中的整数之间的差异。
但是,在我的实现中,使用两个线程的函数比单线程函数慢。我想知道为什么是原因,以及如何正确实现线程以便它运行得更快。
这是代码:
#include <iostream>
#include <vector>
#include <thread>
#include <future>
#include <math.h>
using namespace std;
vector<int> vector_generator(int size) {
vector<int> temp;
for (int i = 0; i < size; i++) {
temp.push_back(i);
}
return temp;
}
vector<int> dist_calculation(int center, vector<int> &input, int start, int end) {
vector<int> temp;
for (int i = start; i < end; i++) {
temp.push_back(abs(center - input[i]));
}
return temp;
}
void multi_dist_calculation(int center, vector<int> &input) {
int mid = input.size() / 2;
vector<int> temp1(input.begin(), input.begin() + mid);
vector<int> temp2(input.begin()+mid, input.end());
auto future1 = async(dist_calculation, center, temp1, 0, mid);
auto future2 = async(dist_calculation, center, temp2, 0, mid);
vector<int> result1 = future1.get();
vector<int> result2 = future2.get();
return;
}
int main() {
vector<int> v1 = vector_generator(1000000000);
vector<int> result;
multi_dist_calculation(0, v1);
//dist_calculation(50, v1, 0, v1.size());
return 0;
}
更新#1
添加了std::launch::async和reserve()的建议,它确实使代码更快。但是 2 线程函数仍然比单线程函数慢。我可以说在这种计算中,单线程更快吗?
#include <iostream>
#include <vector>
#include <thread>
#include <future>
#include <math.h>
using namespace std;
vector<int> vector_generator(int size) {
vector<int> temp;
temp.reserve(size);
for (int i = 0; i < size; i++) {
temp.push_back(i);
}
return temp;
}
vector<int> dist_calculation(int center, vector<int> &input, int start, int end) {
vector<int> temp;
temp.reserve(end - start);
for (int i = start; i < end; i++) {
temp.push_back(abs(center - input[i]));
}
return temp;
}
void multi_dist_calculation(int center, vector<int> &input) {
int mid = input.size() / 2;
auto future1 = async(std::launch::async, dist_calculation, center, input, 0, mid);
auto future2 = async(std::launch::async, dist_calculation, center, input, mid, input.size());
vector<int> result1 = future1.get();
vector<int> result2 = future2.get();
return;
}
int main() {
vector<int> v1 = vector_generator(1000000000);
vector<int> result;
int center = 0;
multi_dist_calculation(center, v1);
//dist_calculation(center, v1, 0, v1.size());
return 0;
}
解决方案
你没有传递任何std::launch policy
to std::async
,所以它给实现留下了很大的自由。
表现得好像 (2) 被调用,策略为 std::launch::async | 标准::启动::延迟。换句话说, f 可以在另一个线程中执行,也可以在查询结果 std::future 以获取值时同步运行。
但也请注意,更一般地,使用更多线程,尤其是在小任务上可能不会更快。
- 您要处理的任何任务
dist_calculation
或任何任务都是少量工作,请注意开销。创建一个新线程的成本相对较高,而且无论内部池的std::async
使用、承诺和未来如何,都会产生开销。 - 此外,按照编写的方式,您可能会创建更多的向量,具有更多的动态内存,并且您需要合并结果,这也会产生一些成本。
- 在更复杂的情况下,如果
std::mutex
涉及同步(例如 with),则可能会比额外线程获得的性能花费更多的性能。 - 在某些情况下,瓶颈不会是 CPU。例如,它可能是磁盘/存储速度(包括页面/交换文件)、网络速度(包括远程服务器),甚至内存带宽(除了 NUMA 感知优化,它们比仅使用复杂得多
std::async
)。这些中的多线程只会增加开销,但没有好处。
您应该首先在可能的情况下使用其他基本优化,例如reserve
向量的大小以避免不必要的分配和复制,也许resize
并使用 the vector[index] = a
instead ofpush_back
等。
对于一些简单的事情,abs(centre - input[i])
您可能会从 SIMD(单指令多数据)优化中获得更多改进。例如,确保您正在编译任何优化,例如SSE2
启用,并且如果编译器没有适当地优化循环(我认为push_back
可能会干扰,测试!),稍微改变它,或者甚至可能明确地使用向量指令(对于 x86 签出_mm_add_epi32
等)。