使用多线程时程序运行速度较慢
我有一个简单的程序可以完成一些蒙特卡罗算法。算法n的一次迭代没有副作用,所以我应该能够使用多个线程运行它。因此,这是my whole program的相关部分,这是写在C++ 11:使用多线程时程序运行速度较慢
void task(unsigned int max_iter, std::vector<unsigned int> *results, std::vector<unsigned int>::iterator iterator) {
for (unsigned int n = 0; n < max_iter; ++n) {
nume::Album album(535);
unsigned int steps = album.fill_up();
*iterator = steps;
++iterator;
}
}
void aufgabe2() {
std::cout << "\nAufgabe 2\n";
unsigned int max_iter = 10000;
unsigned int thread_count = 4;
std::vector<std::thread> threads(thread_count);
std::vector<unsigned int> results(max_iter);
std::cout << "Computing with " << thread_count << " threads" << std::endl;
int i = 0;
for (std::thread &thread: threads) {
std::vector<unsigned int>::iterator start = results.begin() + max_iter/thread_count * i;
thread = std::thread(task, max_iter/thread_count, &results, start);
i++;
}
for (std::thread &thread: threads) {
thread.join();
}
std::ofstream out;
out.open("out-2a.csv");
for (unsigned int count: results) {
out << count << std::endl;
}
out.close();
std::cout << "Siehe Plot" << std::endl;
}
令人费解的是,它变慢线程多我补充。随着4个线程,我得到这个:
real 0m5.691s
user 0m3.784s
sys 0m10.844s
而使用一个单独的线程:
real 0m1.145s
user 0m0.816s
sys 0m0.320s
我意识到,移动CPU内核之间的数据可能会增加开销,但vector
应在启动时宣布,而不是在中间修改。在多核上,这是否有什么特别的原因?
我的系统是一个i5-2550M,其具有4个内核(2 +超线程)和I用克++(Ubuntu的/ Linaro的4.7.3-1ubuntu1)4.7.3
更新我看到不使用螺纹(1),它会产生大量的用户负载的,而具有螺纹(2)中,将具有比用户负载更多的内核:
10K运行:
http://wstaw.org/m/2013/05/08/stats3.png
100K上运行:
http://wstaw.org/m/2013/05/08/Auswahl_001.png
随着100K运行时,我得到如下:
没有线程都:
real 0m28.705s
user 0m28.468s
sys 0m0.112s
用于的每个部分螺纹程序。那些部分甚至不使用相同的内存,所以我对同一个容器的并发应该也是一样。但它需要较长的方式:
real 2m50.609s
user 2m45.664s
sys 4m35.772s
因此,尽管三个主要部分占用我的CPU 300%,他们采取6倍长。
随着1M的运行,花了real 4m45
去做。我以前运行过1M,并且至少需要real 20m
,即使不是real 30m
。
评估您在GitHub上的当前main.cpp。除了上面提供的意见:
- 是,兰特()不是线程安全的,从而有可能是值得运行的多线程业务逻辑(这种方式之前预先填充一些阵列随机值,你减少可能的锁的数量)。如果您计划执行一些堆活动(在多线程之前进行预分配或使用自定义的每线程分配器),则内存分配也是如此。
- 不要忘记其他过程。如果您打算在4核上使用4个线程,这意味着您将与其他软件(至少是OS例程)竞争CPU资源。
- 文件输出是一个大的储物柜玩家。你在每次循环迭代时都会执行“< <”运算符,并且它会花费很多成本(我记得过去有一个有趣的案例:做一个日志输出,间接地修复了一个多线程错误,因为通用记录器是锁定驱动的,某种同步原语,请注意!)。
- 最后,没有任何形式的保证,多线程应用程序可能比单线程更快。有一些CPU特定的,特定于环境的等方面。
矢量对象结果被创建的所有线程共享的,所以即使你的问题是一个尴尬的并行,由于共享对象,有竞争就更不用说高速缓存未命中(我不够好解释关于现代架构中的缓存)。可能你应该有n个线程的n个结果向量,并最终合并结果。我猜,这会加快速度。
另一个提示是尽可能使用std :: async而不是线程。它处理线程分配和其他低级别混乱。我从Scott Mayer的有效C++ 11书中读到它。但是,通过使用线程,可以将线程关联设置为特定的核心。所以,如果你的处理器支持8个线程,你可以创建8个线程,并且至少在Linux上为每个线程分配每个线程。
'10000'真的很小...尝试一个更大的数字。 – UmNyobe 2013-05-08 09:32:55
可能的上下文切换开销占据了执行此任务所需的时间。正如所建议的那样,向“10000”添加几个零... – 2013-05-08 09:34:56
创建线程也有开销。让任务做一个简单的“返回”,看看有多少这些数字是实际的计算。也可以尝试不创建线程(只需从当前的任务函数运行),它应该会更快。与启动线程所需的操作系统相比,10K迭代可能没有任何意义。 – hamstergene 2013-05-08 09:42:07