我在C中实施了一个小程序,使用蒙特卡罗方法计算PI(主要是因为个人兴趣和培训).在实现了基本代码结构之后,我添加了一个命令行选项,允许执行线程计算.
我预计会有很大的加速,但我很失望.命令行概要应该是清楚的.用于近似PI的最终迭代次数是通过命令行传递的-iterations和-threads的乘积. Leaving -threads blank将其默认为1个线程,导致在主线程中执行.
下面的测试总共进行了80万次迭代测试.
在Windows 7 64Bit(Intel Core2Duo Machine)上:
使用Cygwin GCC 4.5.3编译:gcc-4 pi.c -o pi.exe -O3
在Ubuntu / Linaro 12.04(8核心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);
}
题
为什么是这样?为什么Linux上存在这种极端差异?我预计计算的时间至少是原始时间的3/4.当然有可能我只是错误地使用了pthread库.在这种情况下如何做正确的澄清将是非常好的.