【发布时间】:2015-01-20 12:01:48
【问题描述】:
我有一个小的 C 程序,它使用 monte-carlo-simulation 计算 pi,它基本上只是测试随机点 [x,y] 是在圆内还是圆外。
为了逼近 pi,我必须使用大量的样本 n,其直接比例复杂度为 O(n)。所以为了计算大量的样本n,我实现了POSIX threads api来并行计算能力。
我的代码如下所示:
pthread_t worker[nthreads]; /* creates workers for each thread */
struct param aparam[nthreads]; /* struct param{ long* hits; long rounds; }; */
long nrounds = nsamples / nthreads; /* divide samples to subsets of equal rounds per thread */
for (int i = 0; i < nthreads; ++i) { /* loop to create threads */
aparam[i].hits = 0;
aparam[i].rounds = nrounds;
pthread_create(&worker[i], NULL, calc_pi, &aparam[i]); /* calls calc_pi(void* vparam){} */
}
long nhits = 0;
for (int j = 0; j < nthreads; ++j) { /* collects results */
pthread_join(worker[j], NULL);
nhits += (long)aparam[j].hits; /* counts hits inside the cicrle */
}
这就是每个线程正在做的事情:
void* calc_pi(void* vparam)
{ /* counts hits inside a circle */
struct param *iparam;
iparam = (struct param *) vparam;
long hits = 0;
float x, y, z;
for (long i = 0; i < iparam->rounds; ++i) {
x = (float)rand()/RAND_MAX;
y = (float)rand()/RAND_MAX;
z = x * x + y * y;
if (z <= 1.f) /* circle radius of 1 */
++hits;
}
iparam->hits = (long*)hits;
return NULL;
}
现在我有一个奇怪的观察。使用相同的样本集 n 并且随着线程数量的增加 i,这个程序需要 更多的时间而不是更少的时间。
以下是一些平均运行时间(可重现):
-------------------------------------------------
| Threads[1] | Samples[1] | Rounds[1] | Time[s] |
-------------------------------------------------
| 32 | 268435456 | 8388608 | 118 |
| 16 | 268435456 | 16777216 | 106 |
| 8 | 268435456 | 33554432 | 125 |
| 4 | 268435456 | 67108864 | 152 |
| 2 | 268435456 | 134217728 | 36 |
| 1 | 268435456 | 268435456 | 15 |
-------------------------------------------------
例如,为什么两个线程执行相同的工作所花费的时间是单个线程的两倍以上?我的假设是划分工作的两个线程应该将时间减少至少 50%。
使用 GCC 4.9.1 和以下标志编译:
gcc -O2 -std=gnu11 -pthread pipa.c -lpthread -o pipa
我的硬件是双 Intel Xeon E5520(2 个处理器,每个 4 核)@ 2.26 GHz,禁用超线程,运行 2.6.18 内核的科学 linux。
有什么想法吗?
【问题讨论】:
-
Linux 2.6.18 是古老的。像,史前。我很确定从那时起多线程程序有很多改进。例如,您使用的是哪个 pthreads 实现? LinuxThreads 还是 NPTL?
-
你确定线程在不同的内核上运行吗?也许出于某种原因,它们共享同一个内核,因此上下文切换开销会增加运行时间
-
rand() 可能会导致争用。
-
EOF,我可以在 linux 3.17.3 上重现这个;埃里克,我用 htop 进行了检查,线程正在使用所有内核。 2501,rand()好像是问题,使用rand_r()可以提高性能。
标签: c multithreading performance pthreads multiprocessing