当使用多线程时,程序会变慢
Program is slower when using multiple threads
我有一个简单的程序,做一些蒙特卡罗算法。算法的一次迭代没有副作用,所以我应该能够在多个线程中运行它。这是我整个程序的相关部分,它是用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 2n";
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 +超线程),我使用g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
<标题> 更新我看到在没有线程(1)的情况下,它将有很多用户负载,而在有线程(2)的情况下,它将有比用户负载更多的内核:
10 k:
http://wstaw.org/m/2013/05/08/stats3.png100 k:
http://wstaw.org/m/2013/05/08/Auswahl_001.png当前main.cpp
运行100K,得到如下结果:
没有线程:
real 0m28.705s
user 0m28.468s
sys 0m0.112s
程序的每个部分的线程。这些部分甚至不使用相同的内存,因此相同容器的I并发性也应该排除。但它需要更长的时间:
real 2m50.609s
user 2m45.664s
sys 4m35.772s
因此,虽然这三个主要部分占用了我的CPU的300%,但它们需要6倍的时间。
在1M运行时,需要real 4m45
来完成。我以前运行过1M,它至少需要real 20m
,如果不是real 30m
的话。
在GitHub中评估当前的main.cpp。除了上面提供的注释之外:
- 是的,rand()不是线程安全的,因此在运行多线程业务逻辑之前,有必要预先用随机值填充一些数组(这样可以减少可能的锁数量)。如果您计划进行一些堆活动(在多线程之前进行预分配或使用自定义的每线程分配器),那么内存分配也是如此。
- 不要忘记其他进程。如果您计划在4核上使用4个线程,这意味着您将与其他软件(至少是操作系统例程)争夺CPU资源。
- 文件输出是一个大的储物柜播放器。您在每次循环迭代上执行"<<"运算符,这会花费您很多(我记得我过去的一个有趣的例子:做一个日志输出间接地修复了一个多线程错误。因为通用记录器是锁驱动的,所以它是某种同步原语,请注意!最后,没有任何形式的保证,多线程应用程序可以比单线程更快。有一堆特定于cpu,特定于环境等方面。
vector对象的结果被创建的所有线程共享,因此即使您的问题是一个令人尴尬的并行,由于共享对象,也存在一个争论,不要提及缓存丢失(我不足以解释现代架构上的缓存)。也许你应该为你的n个线程提供n个结果向量,并最终合并结果。我想那会加快速度的。
要提到的另一个技巧是尽可能使用std::async而不是thread。它处理线程分配和其他低级混乱。我是从Scott Mayer的有效c++11书中读到的。但是,通过使用线程,您可以将线程关联设置为特定的核心。所以,如果你的处理器支持8个线程,你至少可以在linux上创建8个线程并将每个线程分配给每个内核。
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- sigwait() 在多线程程序中不起作用
- 多线程程序中出现意外的内存泄漏
- 通过安装信号处理程序关闭多线程应用程序
- 多线程减慢程序速度:无错误共享,无互斥锁,无缓存未命中,无小工作量
- C++多线程程序:变量定义为类成员的隔离错误
- 多线程 gtkmm 应用程序最简单的示例
- 将数组作为多线程应用程序中函数的返回传递
- 修改多线程应用程序中的对象
- 在以读取为主的多线程程序中,可以使用原子来减少锁定吗
- 多线程程序中的分段故障和gdb回溯上的不完整信息
- 多线程程序卡在优化模式下,但在 -O0 中正常运行
- 多线程 C++11 应用程序中的同步
- 多线程Windows GUI应用程序中的死锁
- 在使用 std::cout 和多线程程序中如何避免数据竞争<iomanip>?
- 控制多线程程序中的输出流
- C++多线程应用程序将永远挂起
- 具有多线程应用程序的 Nanomsg 无阻塞双向套接字
- C++从多线程 CPU 程序迁移到 GPU
- C++应用程序多线程中的锁定方法