我尝试使用std库,特别是线程库。 我们的想法是在有多线程和无多线程的情况下填充矩阵。我有8个核心。
void fillMatrix(int ID, std::vector<std::vector<double>> & lMatrix,int inThread){
for (int i = 0; i < 10000; ++i){
if (i % inThread == ID){
for (int j = 0; j < 10000; ++j){
lMatrix[i][j] = 123456.0;
}
}
}
}
void testMT(int inThread){
std::vector<std::thread> lPool;
std::vector<std::vector<double>> lMatrix(10000, std::vector<double>(10000));
for (int i = 0; i < inThread; ++i){
lPool.push_back(std::thread(std::bind(&fillMatrix,i, lMatrix,inThread)));
}
for (std::thread & t : lPool){
t.join();
}
}
主要代码:
int main(){
const clock_t begin_time1 = clock();
testMT(1);
std::cout << float(clock() - begin_time1) / CLOCKS_PER_SEC;
}
testMT(1)运行需要2.1秒,而testMT(8)需要7.032秒。
有什么想法吗? 感谢。
答案 0 :(得分:5)
你有一个非常糟糕的 if 会减慢它。
在1个线程的情况下总是如此,但是在8个线程的情况下它是真的然后是假的假...是的。分支预测在这里失败。
将第一个for循环拆分/分割到每个线程要好得多。就像线程1执行矩阵的前1/8,线程2执行第二个1/8,依此类推。
类似的东西:
for(int i = 10000*ID/inThread; i< 10000*(ID+1)/inThread; ++i)
在ID = 0的情况下,循环将从0变为2500,ID = 1将从2500变为5000,依此类推。
答案 1 :(得分:4)
您的线程都在修改附近内存位置中的相同对象。这意味着内存的所有权必须不断地从线程到线程进行乒乓。
这不是线程的合理使用。如果你希望在众多线程同时紧密地操纵同一个对象时保持性能,则需要专业知识来处理虚假共享等事情。
答案 2 :(得分:4)
您的代码无法按您的意愿运行。线程运行后,您会注意到lMatrix
的所有元素都未设置为123456.0
。这是因为std::bind
将向量复制到自身中,然后将其发送到线程。您需要在绑定调用中使用std::ref(lMatrix)
才能使其正常工作并使用相同的矩阵。
更改
std::bind(&fillMatrix,i, lMatrix,inThread)
到
std::bind(&fillMatrix, i, std::ref(lMatrix), inThread)
因此,执行时间增加的很大一部分可能是由复制开销引起的;每次线程启动时进行10000 x 10000次分配和复制(然后是解除分配)。
答案 3 :(得分:0)
在某种程度上,这是一个非常重要的问题。
多线程代码总是比单线程代码慢! (最好的情况是,你仍然需要支付启动和停止线程的费用)
并发使事情变得更快(有时)。
您的目标是从并发中获得的收益超过使用线程的成本 - 并且具有如此重要的好处,以至于“代价”增加了代码的复杂性。此示例未达到该目标。