(正确且有指导意义的回答,见下文)
我开始用 matlab 和 gpu (nvidia gtx660) 做实验。
现在,我编写了这个简单的蒙特卡罗算法来计算 PI。以下是CPU版本:
function pig = mc1vecnocuda(n)
countr=0;
A=rand(n,2);
for i=1:n
if norm(A(i,:))<1
countr=countr+1;
end
end
pig=(countr/n)*4;
end
这需要很少的时间在 CPU 上执行,将 100000 个点“扔”到单位圆中:
>> tic; mc1vecnocuda(100000);toc;
Elapsed time is 0.092473 seconds.
相反,请参阅算法的 gpu 化版本会发生什么:
function pig = mc1veccuda(n)
countr=0;
gpucountr=gpuArray(countr);
A=gpuArray.rand(n,2);
parfor (i=1:n,1024)
if norm(A(i,:))<1
gpucountr=gpucountr+1;
end
end
pig=(gpucountr/n)*4;
end
现在,这需要很长时间才能执行:
>> tic; mc1veccuda(100000);toc;
Elapsed time is 21.137954 seconds.
我不明白为什么。我对 1024 个工作人员使用 parfor 循环,因为用 gpuDevice 查询我的 nvidia 卡,1024 是 gtx660 上允许的最大并发线程数。
有人能帮我吗?谢谢。
编辑:这是避免 IF 的更新版本:
function pig = mc2veccuda(n)
countr=0;
gpucountr=gpuArray(countr);
A=gpuArray.rand(n,2);
parfor (i=1:n,1024)
gpucountr = gpucountr+nnz(norm(A(i,:))<1);
end
pig=(gpucountr/n)*4;
end
这是按照 Bichoy 的指导方针编写的 代码(实现结果的正确代码):
function pig = mc3veccuda(n)
countr=0;
gpucountr=gpuArray(countr);
A=gpuArray.rand(n,2);
Asq = A.^2;
Asqsum_big_column = Asq(:,1)+Asq(:,2);
Anorms=Asqsum_big_column.^(1/2);
gpucountr=gpucountr+nnz(Anorms<1);
pig=(gpucountr/n)*4;
end
请注意 n=10 百万的执行时间:
>> tic; mc3veccuda(10000000); toc;
Elapsed time is 0.131348 seconds.
>> tic; mc1vecnocuda(10000000); toc;
Elapsed time is 8.108907 seconds.
我没有测试我原来的 cuda 版本(for/parfor),因为它的执行需要几个小时,n=10000000。
伟大的比乔伊!;)