假设我有一个9000+迭代的for循环,我想以某种方式用线程改进它,比如10。
Function Something(){
for ( i = 0; i < 9000 ){
DoStuff();
}
}
用10个线程覆盖9000次迭代的最佳方法是什么?我目前正在使用C ++ 99和win32 pthreads,但我认为这是一个通用的问题。
提前致谢。
编辑:对于这个例子,让我们说DoStuff()处理繁重的处理,独立于其他迭代。此外,还有共享资源,但这些资源都包含互斥变量。
答案 0 :(得分:3)
答案真的取决于DoStuff()
实际做了什么。如果它是一个大的矢量,你正在与另一个大(或小)矢量相乘,那么将它切成10个部分可能并不困难。这适用于任何CPU密集型工作,其中每个计算独立于其他计算。计算所有元素的总和也可以正常工作,但是你必须总结一个部分,然后存储结果,当所有线程完成时,总结不同的部分。
还有一些计算对并行化完全没用。计算使用F(N)= F(N-1)+斐波那契数F(N-2)的方法将不会在线程在所有的工作良好,因为你需要前一步骤的结果,然后才可以计算出当前步。
如果,在另一方面DoStuff
从一个单一的文件看10万条记录,这是不太可能有更多的线程将在所有帮助 - 因为读取文件按顺序一个比散射快一点遍读这个地方,磁盘比处理器慢很多,所以你不会获得任何东西。
答案 1 :(得分:0)
取决于DoStuff()
内的内容。如果其中的数据依赖于其他迭代,或者访问更新的外部数据并且必须在DoStuff()
次运行之间共享,那么线程甚至可能会减慢速度。如果DoStuff()
能够独立运行并且有自己的位置来存储不与其他线程冲突的内存,并且需要足够长的时间来运行以克服设置线程和加入它们的初始开销完成后,在循环上方创建10个线程,通过在每个线程中放置900个迭代来运行代码,并在完成时加入/终止它们。或者使用线程池构造并让它为您完成。
通用问题的通用答案。
答案 2 :(得分:0)
一种方法是将循环的部分委托给不同的线程。让一个线程处理范围0-999,第二个线程处理范围从1000-1999,依此类推。伪代码如下:
Function Thread(int start, int count){
for ( i = start; i < (start + count); ++i ){
DoStuff();
}
}
Function Something(){
for ( i = 0; i < 9; ++i ){
SpawnThread(Thread, (i * 1000), 1000);
}
}
答案 3 :(得分:0)
根据您的编辑,我觉得可能有一个根本不涉及显式线程的解决方案。您可能能够使用OpenMP并行执行代码,而根本不进行明确的线程处理。这可以像下面这样简单:
Function Something(){
#pragma omp parallel for // ...
for ( i = 0; i < 9000 ){
DoStuff();
}
}
此处,...
表示您可能需要(或想要)在那里添加更多注释。例如,您可以指定将共享哪些变量,这些变量对于每个线程都是独立的,等等。
这可能比编写自己的线程代码要轻松得多,但它可能非常有效。特别是,OpenMP运行时通常会有内置代码,用于根据可用的处理器资源确定要使用的线程数,因此使用10个线程并不明确 - 所以在几年内你有一个拥有16个内核的机器,你不必重写它们就可以利用它们。
与此同时,OpenMP确实存在局限性。对于你所描述的情况(并行执行循环迭代),它可以很好地工作。它几乎不适合其他一些场景(例如,创建一个执行管道,因此一个处理步骤发生在一个核心上,下一个核心发生在下一个核心上,等等。)