我有一个简单的程序可以执行一些蒙特卡罗算法。使用algorithmn的一次迭代没有副作用,因此我应该能够使用多个线程运行它。所以这是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 +超线程),我使用g ++(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
因此虽然三个主要部分占用了我300%的CPU,但它们需要6倍的时间。
使用1M运行,需要real 4m45
。我以前运行过1M,如果不是real 20m
,则至少花费real 30m
。
答案 0 :(得分:5)
在GitHub上评估你当前的main.cpp。除了上面提供的评论:
答案 1 :(得分:1)
vector对象的结果由创建的所有线程共享,所以即使你的问题是一个令人尴尬的并行,由于共享对象,还有一个争论,更不用说缓存未命中(我不足以解释缓存在现代建筑上)。可能你应该有n个线程的n个结果向量,最后合并结果。我想这会加快速度。
要提到的另一个提示是尽可能使用std :: async而不是线程。它处理线程分配和其他低级别的混乱。我是从Scott Mayer的有效c ++ 11书中读到的。但是,通过使用线程,您可以将线程关联设置为特定核心。因此,如果您的处理器支持8个线程,您可以创建8个线程,并至少在linux上为每个核心分配每个线程。