我用 C 语言实现了一个小程序,使用 Monte Carlo 方法计算 PI(主要是因为个人兴趣和培训)。在实现了基本的代码结构之后,我添加了一个命令行选项,允许执行线程计算。
我预计会大幅提速,但我感到失望。命令行概要应该清楚。近似 PI 的最终迭代次数是通过命令行传递的次数-iterations
的乘积。-threads
留空-threads
默认为1
线程,导致在主线程中执行。
下面的测试总共进行了 8000 万次迭代。
在 Windows 7 64 位(Intel Core2Duo 机器)上:
使用 Cygwin GCC 4.5.3 编译:gcc-4 pi.c -o pi.exe -O3
在 Ubuntu/Linaro 12.04 (8Core AMD) 上:
使用 GCC 4.6.3 编译:gcc pi.c -lm -lpthread -O3 -o pi
表现
在 Windows 上,线程版本比非线程版本快几毫秒。老实说,我期待更好的表现。在 Linux 上,哇!有没有搞错?为什么甚至需要 2000% 的时间?当然,这在很大程度上取决于实现,所以就这样吧。命令行参数解析完成并开始计算后的摘录:
// Begin computation.
clock_t t_start, t_delta;
double pi = 0;
if (args.threads == 1) {
t_start = clock();
pi = pi_mc(args.iterations);
t_delta = clock() - t_start;
}
else {
pthread_t* threads = malloc(sizeof(pthread_t) * args.threads);
if (!threads) {
return alloc_failed();
}
struct PIThreadData* values = malloc(sizeof(struct PIThreadData) * args.threads);
if (!values) {
free(threads);
return alloc_failed();
}
t_start = clock();
for (i=0; i < args.threads; i++) {
values[i].iterations = args.iterations;
values[i].out = 0.0;
pthread_create(threads + i, NULL, pi_mc_threaded, values + i);
}
for (i=0; i < args.threads; i++) {
pthread_join(threads[i], NULL);
pi += values[i].out;
}
t_delta = clock() - t_start;
free(threads);
threads = NULL;
free(values);
values = NULL;
pi /= (double) args.threads;
}
虽然pi_mc_threaded()
实现为:
struct PIThreadData {
int iterations;
double out;
};
void* pi_mc_threaded(void* ptr) {
struct PIThreadData* data = ptr;
data->out = pi_mc(data->iterations);
}
您可以在http://pastebin.com/jptBTgwr找到完整的源代码。
问题
为什么是这样?为什么在 Linux 上有这种极端差异?我预计计算所需的时间至少是原始时间的 3/4。当然,我可能只是错误地使用了该pthread
库。在这种情况下如何做正确的澄清会非常好。