首页 > 解决方案 > 使用并行编程计算总和

问题描述

我想将 1 加到一个数字(0)上 100 亿次。我尝试了两种方法 -

  1. 使用单个线程(主线程)来完成工作。
  2. 创建两个线程并在第一个线程中执行一半的加法,在第二个线程中执行另一半。

我期待第二种方法比第一种方法花费更少的时间,但结果
恰恰相反。以下是分别使用多线程方法和单线程
(主线程)的时序。

real    0m35.661s    
user    1m6.652s
sys 0m0.004s

real    0m25.162s
user    0m25.162s
sys 0m0.000s

以下是源代码。

#include <stdio.h>
#include <pthread.h>

static unsigned long long int sum1, sum2;
long long unsigned int l1 = 10000000000/2;
long long unsigned int l2 = 10000000000/2 + 1;  

void *thread1(void *arg)
{
    unsigned long long int i;
    printf("%s\n", __func__);
    for (i=0;i<l1; i++)
        sum1 += 1;

    pthread_exit((void *)0);
}

void *thread2(void *arg)
{
    unsigned long long int i;
    printf("%s\n", __func__);
#if 0
    /* In case of single thread, the following for loop is used */
    for (i=0;i<10000000000; i++)
        sum2 += 1;
#endif
    for (i=l2;i<10000000000; i++)
        sum2 += 1;

    pthread_exit((void *)0);
}

int main(void)
{
    pthread_t tid1, tid2;
    void *res1, *res2;
    void *(*tptr)(void *);

    printf("%llu, %llu\n", l1, l2);
    /* all pthread_* calls are disabled in single thread mode
     * only main thread used which calls -thread2- method */
    pthread_create(&tid1, NULL, &thread1, NULL);

    pthread_create(&tid2, NULL, &thread2, NULL);

    if(pthread_join(tid1, NULL))
            printf("Error joining with t1");
    if(pthread_join(tid2, NULL))
            printf("Error joining with t2");

/* Enable  for single thread mode */
#if 0
    tptr = thread2;
    tptr(NULL);
#endif
    printf("Main thread exiting\n");
    return 0;
}

我能想到的一个原因可能是线程的调度开销
在多线程情况下会导致更多时间。对此有更多解释吗?

===============
在尝试接受答案中建议的解决方案后,我
在多线程情况下看到以下读数 -

real    0m12.526s
user    0m23.375s
sys 0m0.004s

正如预期的那样,几乎是我用单线程得到的一半。

标签: cmultithreadingparallel-processingpthreads

解决方案


问题是虚假分享sum1并且sum2存储在同一缓存行中,因此对它们的存储是竞争的,这导致了序列化。

您可以使用alignas强制它们分隔缓存行。

alignas(64) static unsigned long long int sum1, sum2;

然而,这都是不使用优化的产物。将总和的中间值存储在 RAM 中是没有意义的,它应该在寄存器中,如果您在启用优化的情况下进行编译,编译器可能会这样做。然而,它也会消除整个循环,因为重复添加的效果是可以预测的。


推荐阅读