使用并行编程计算总和
Calculating sum using parallel programming
我想将 1 加到一个数字 (0) 上 100 亿次。我尝试了两种方法 -
- 使用单线程(主线程)完成工作。
- 创建两个线程并在第一个线程中执行一半的加法运算,另一半在第二个线程中执行。
我原以为第二种方法比第一种方法花费的时间更少,但结果是
与此相反。以下是使用多线程方法和单线程的时间
(主线程)分别。
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
正如预期的那样,几乎是我使用单线程获得的一半。
问题是虚假分享。 sum1
和 sum2
存储在同一个缓存行中,因此对它们的存储是竞争的,从而导致序列化。
您可以使用alignas
强制它们分隔缓存行。
alignas(64) static unsigned long long int sum1, sum2;
然而,这是不使用优化的所有产物。将总和的中间值存储在 RAM 中是没有意义的,它应该在寄存器中,如果您在启用优化的情况下进行编译,编译器可能会这样做。然而,它也会消除整个循环,因为重复添加的效果是可以预测的。
我想将 1 加到一个数字 (0) 上 100 亿次。我尝试了两种方法 -
- 使用单线程(主线程)完成工作。
- 创建两个线程并在第一个线程中执行一半的加法运算,另一半在第二个线程中执行。
我原以为第二种方法比第一种方法花费的时间更少,但结果是
与此相反。以下是使用多线程方法和单线程的时间
(主线程)分别。
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
正如预期的那样,几乎是我使用单线程获得的一半。
问题是虚假分享。 sum1
和 sum2
存储在同一个缓存行中,因此对它们的存储是竞争的,从而导致序列化。
您可以使用alignas
强制它们分隔缓存行。
alignas(64) static unsigned long long int sum1, sum2;
然而,这是不使用优化的所有产物。将总和的中间值存储在 RAM 中是没有意义的,它应该在寄存器中,如果您在启用优化的情况下进行编译,编译器可能会这样做。然而,它也会消除整个循环,因为重复添加的效果是可以预测的。