用简单的程序实现慢速多线程

Posted

技术标签:

【中文标题】用简单的程序实现慢速多线程【英文标题】:slow multithreading with a simple procedure 【发布时间】:2012-12-02 17:41:24 【问题描述】:

我正在玩多线程(没有先前的经验),并且有一个简单的函数,通过两个单独的线程从 int main 调用,这些线程只是从 2 个 for 循环中更改(并创建)一个变量。据我所知,两个线程之间没有依赖关系,但一个线程运行我的时间是 2.29 秒,两个时间是 7.11 秒(我本来预计会是 3-4 秒)。

我在带有两个 Intel atom CPU (Ubuntu 10.04) 的上网本上运行 - 我知道这两个线程都不会获得单个 CPU 的完整“所有权”,因为 int main() 进程本身涉及一个线程(以及无论操作系统需要什么),但我对性能下降感到震惊(大概是线程切换!?)

有什么办法可以在这里改进吗? (可能会减少 CPU 在线程之间跳转所需的工作)。我希望很快能做一些更丰富的事情(使用轮分解进行初筛,其中不同的线程拥有不同的辐条)但我对我现在获得的性能印象并不深刻

我现在的简单代码如下:

#include <iostream>"
#include <ctime>
#include <pthread.h>


void* foo(void* dummyVar)

    for(int i=1; i < 10; i++)
    
        for(int j=1; j < 50000000; j++)
        
            int test = j;
        
            std::cout << i << "\n";
    
    pthread_exit(NULL);


int main(int argc, const char *argv[])

    clock_t start = clock();
    pthread_t thread1;
    pthread_t thread2;
    pthread_attr_t attribute;
    void* status;
    pthread_attr_init(&attribute);
    pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_JOINABLE);
    int i = 0;
    int b = pthread_create(&thread1, NULL, foo, (void*)i);
    int c = pthread_create(&thread2, NULL, foo, (void*)i);
    pthread_join(thread1, &status);
    pthread_join(thread2, &status);

    std::cout << ((double)clock() - start) / CLOCKS_PER_SEC << "\n";
    return 0;

更新:我通过让与 main() 关联的线程在另一个线程也调用 foo(而不是两个线程)之后调用 foo 来获得更好的性能(显然!),尽管这台机器上的多线程仍然较慢(已经对 foo 的一些更改 - 现在只有一个 for 循环 - 时间是 5.17 vs 6.01)

【问题讨论】:

过于原始/短命的任务可能会导致比实际收益更高的线程切换开销。 在您的情况下,您是说线程数超过硬件可用性,即第 1 点。此外,您的线程执行的 I/O 可以忽略不计,因此它们大部分时间都保持忙碌,因此存在彼此之间有更多的争执,并且表现不佳。 我明白了...感谢这里的两个 cmets - 我是否正确地说我为这台机器的未来计划的多线程(用 8 个辐条轮筛)有一个很好的同样注定失败的机会(考虑到它们对于循环来说是相当微不足道的(用一个小函数来获取起点)在素数指标数组中翻转 1)? - 我还没有编写代码,但我看不到每个循环有超过五个指令(以及在辐条之间跳转) 如果有范围,您总是可以设计一个并行算法并为此创建一个程序。即使它在您的机器上表现不佳,但可以在其他一些有更多内核可供线程执行的机器上表现良好。性能与机器有关。 为此干杯...我稍后会用 4 核机器试一试(虽然我还没有)...有什么方法可以预测线程何时切换(所以围绕它设计我的算法)?我试过弄乱我的 foo 函数,但在这里没有得到任何改进 【参考方案1】:
    for(int j=1; j < 50000000; j++)
    
        int test = j;
    

正确的基准测试可能是一门艺术,但这个很快就会失败。此代码生存的唯一方法是忘记打开优化器。在任何体面的编译器上,它都会完全消除循环,因为它没有有用的副作用。

假设你确实打开了优化器,你实际上测量了 10 次

  std::cout << i << "\n";

一个永远不能同时运行的语句,线程将争夺序列化对终端/控制台的访问的锁。与预期结果一样,这确实会变慢。

但很有可能您忘记了优化器,如果没有打开它,永远不要分析代码,您不会以这种方式发布它。

【讨论】:

啊哈!非常感谢您指出这一点-如果我设置了优化标志,编译器肯定会终止循环(是的,我忘记了!)-进一步玩弄并将 foo 之外的静态变量设置为 J+i 的值(它没有(至少在这种情况下)没有优化的副作用)并注释掉 std::cout 我现在通过以下方式获得了多线程的胜利:1.18 vs 1.21

以上是关于用简单的程序实现慢速多线程的主要内容,如果未能解决你的问题,请参考以下文章

使用多线程进行慢速 Ms 互操作

用JAVA多线程实现龟兔赛跑

vb 怎么实现多线程

IIS 慢速多线程

Delphi怎样实现多线程

用java多线程编写哲学家就餐程序 利用多线程技术编写哲学家就餐程序,使之在运行时能演示产生死锁的情况,