使用多线程时程序运行速度较慢

问题描述:

我有一个简单的程序可以完成一些蒙特卡罗算法。算法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

Current main.cpp

随着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

+1

'10000'真的很小...尝试一个更大的数字。 – UmNyobe 2013-05-08 09:32:55

+2

可能的上下文切换开销占据了执行此任务所需的时间。正如所建议的那样,向“10000”添加几个零... – 2013-05-08 09:34:56

+1

创建线程也有开销。让任务做一个简单的“返回”,看看有多少这些数字是实际的计算。也可以尝试不创建线程(只需从当前的任务函数运行),它应该会更快。与启动线程所需的操作系统相比,10K迭代可能没有任何意义。 – hamstergene 2013-05-08 09:42:07

评估您在GitHub上的当前main.cpp。除了上面提供的意见:

  1. 是,兰特()不是线程安全的,从而有可能是值得运行的多线程业务逻辑(这种方式之前预先填充一些阵列随机值,你减少可能的锁的数量)。如果您计划执行一些堆活动(在多线程之前进行预分配或使用自定义的每线程分配器),则内存分配也是如此。
  2. 不要忘记其他过程。如果您打算在4核上使用4个线程,这意味着您将与其他软件(至少是OS例程)竞争CPU资源。
  3. 文件输出是一个大的储物柜玩家。你在每次循环迭代时都会执行“< <”运算符,并且它会花费很多成本(我记得过去有一个有趣的案例:做一个日志输出,间接地修复了一个多线程错误,因为通用记录器是锁定驱动的,某种同步原语,请注意!)。
  4. 最后,没有任何形式的保证,多线程应用程序可能比单线程更快。有一些CPU特定的,特定于环境的等方面。

矢量对象结果被创建的所有线程共享的,所以即使你的问题是一个尴尬的并行,由于共享对象,有竞争就更不用说高速缓存未命中(我不够好解释关于现代架构中的缓存)。可能你应该有n个线程的n个结果向量,并最终合并结果。我猜,这会加快速度。

另一个提示是尽可能使用std :: async而不是线程。它处理线程分配和其他低级别混乱。我从Scott Mayer的有效C++ 11书中读到它。但是,通过使用线程,可以将线程关联设置为特定的核心。所以,如果你的处理器支持8个线程,你可以创建8个线程,并且至少在Linux上为每个线程分配每个线程。