c - 使用并行编程计算总和
问题描述
我想将 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 中是没有意义的,它应该在寄存器中,如果您在启用优化的情况下进行编译,编译器可能会这样做。然而,它也会消除整个循环,因为重复添加的效果是可以预测的。
推荐阅读
- npm - npm start 在新的 React 应用程序中不起作用?
- javascript - 如何根据 JavaScript 中的用户输入返回对象图像文件并在弹出窗口中显示?
- html - 是否可以为自定义属性进行 CSS 转换?
- javascript - 表蚂蚁设计两个渲染
- node.js - 是否可以在文件结束之前停止 pcap-parser
- python - 试图将列传递给函数,得到 keyerror (Pandas)
- youtube-api - 为什么即使我们使用在上一个 API 结果上写的 `nextPageToken` ,收集视频 ID 的请求也会失败?
- c - 在openpty之后ncurses newterm
- c++ - 向量元素的初始化顺序是否有标准保证?
- python - Pythonnet 支持 .NET Core 还是 .NET 5.0