为什么批处理模式比 parfor 快这么多?
Why is batch mode so much faster than parfor?
我正在编写 matlab 代码来执行 3 维积分:
function [ fint ] = int3d_ser(R0, Rf, N)
Nr = N;
Nt = round(pi*N);
Np = round(2*pi*N);
rs = linspace(R0, Rf, Nr);
ts = linspace(0, pi, Nt);
ps = linspace(0, 2*pi, Np);
dr = rs(2)-rs(1);
dt = ts(2)-ts(1);
dp = ps(2)-ps(1);
C = 1/((4/3)*pi);
fint = 0.0;
for ir = 2:Nr
r = rs(ir);
r2dr = r*r*dr;
for it = 1:Nt-1
t = ts(it);
sintdt = sin(t)*dt;
for ip = 1:Np-1
p = ps(ip);
fint = fint + C*r2dr*sintdt*dp;
end
end
end
end
对于关联的 int3d_par
(parfor) 版本,我打开了一个 matlab 池,并将 for
替换为 parfor
。我在更多内核上 运行 获得了相当不错的加速(我的测试是从 2 到 8 个内核)。
但是,当我 运行 以批处理模式进行相同的集成时:
function [fint] = int3d_batch_cluster(R0, Rf, N, cluster, ncores)
%%% note: This will not give back the same value as the serial or parpool version.
%%% If this was a legit integration, I would worry more about even dispersion
%%% of integration nodes per core, but I just want to benchmark right now so ... meh
Nr = N;
Nt = round(pi*N);
Np = round(2*pi*N);
rs = linspace(R0, Rf, Nr);
ts = linspace(0, pi, Nt);
ps = linspace(0, 2*pi, Np);
dr = rs(2)-rs(1);
dt = ts(2)-ts(1);
dp = ps(2)-ps(1);
C = 1/((4/3)*pi);
rns = floor( Nr/ncores )*ones(ncores,1);
RNS = zeros(ncores,1);
for icore = 1:ncores
if(sum(rns) ~= Nr)
rns(icore) = rns(icore)+1;
end
end
RNS(1) = rns(1);
for icore = 2:ncores
RNS(icore) = RNS(icore-1)+rns(icore);
end
rfs = rs(RNS);
r0s = zeros(ncores,1);
r0s(2:end) = rfs(1:end-1);
j = createJob(cluster);
for icore = 1:ncores
r0 = r0s(icore);
rf = rfs(icore);
rn = rns(icore);
trs = linspace(r0, rf, rn);
t{icore} = createTask(j, @int3d_ser, 1, {r0, rf, rn});
end
submit(j);
wait(j);
fints = fetchOutputs(j);
fint = 0.0;
for ifint = 1:length(fints)
fint = fint + fints{ifint};
end
end
我注意到它要快得多。为什么以批处理模式进行此集成与在 parfor
中进行集成不同?
作为参考,我使用 N
测试代码,从 10 和 20(以获取 运行 时间的多项式近似中的常数)到 1000 和 2000 等较大数字。该算法将三次缩放,因为我将 theta
和 phi
方向上的积分节点数指定为给定 N
.
的常数倍数
对于 2000 个节点,parfor
版本大约需要 630 秒,而批处理模式下相同数量的节点大约需要 19 秒(其中大约 12 秒只是开销通信,我们也获得了 10 集成节点)。
在与 Mathworks
支持人员交谈后,我似乎对 parfor
的工作原理存在根本性的误解。我的印象是 parfor
表现得像 openMP
,而批处理模式在共享内存和分布式内存方面表现得像 mpi
。
原来parfor
其实也用到了分布式内存。当我创建 4 个批处理函数时,创建新进程的开销发生了 4 次。我认为使用 parfor
会导致该开销仅发生 1 次,然后 parfor
将在同一内存 space 中发生。事实并非如此。
在我的示例代码中,事实证明,对于 parfor
的每次迭代,我实际上都在承担创建新线程的开销。比较 'apples to apples' 时,我实际上应该创建与 parfor
循环中的迭代相同数量的批处理调用。这就是 parfor
函数花费如此长的时间的原因 - 我为多处理招致了 很多 的开销。
我正在编写 matlab 代码来执行 3 维积分:
function [ fint ] = int3d_ser(R0, Rf, N)
Nr = N;
Nt = round(pi*N);
Np = round(2*pi*N);
rs = linspace(R0, Rf, Nr);
ts = linspace(0, pi, Nt);
ps = linspace(0, 2*pi, Np);
dr = rs(2)-rs(1);
dt = ts(2)-ts(1);
dp = ps(2)-ps(1);
C = 1/((4/3)*pi);
fint = 0.0;
for ir = 2:Nr
r = rs(ir);
r2dr = r*r*dr;
for it = 1:Nt-1
t = ts(it);
sintdt = sin(t)*dt;
for ip = 1:Np-1
p = ps(ip);
fint = fint + C*r2dr*sintdt*dp;
end
end
end
end
对于关联的 int3d_par
(parfor) 版本,我打开了一个 matlab 池,并将 for
替换为 parfor
。我在更多内核上 运行 获得了相当不错的加速(我的测试是从 2 到 8 个内核)。
但是,当我 运行 以批处理模式进行相同的集成时:
function [fint] = int3d_batch_cluster(R0, Rf, N, cluster, ncores)
%%% note: This will not give back the same value as the serial or parpool version.
%%% If this was a legit integration, I would worry more about even dispersion
%%% of integration nodes per core, but I just want to benchmark right now so ... meh
Nr = N;
Nt = round(pi*N);
Np = round(2*pi*N);
rs = linspace(R0, Rf, Nr);
ts = linspace(0, pi, Nt);
ps = linspace(0, 2*pi, Np);
dr = rs(2)-rs(1);
dt = ts(2)-ts(1);
dp = ps(2)-ps(1);
C = 1/((4/3)*pi);
rns = floor( Nr/ncores )*ones(ncores,1);
RNS = zeros(ncores,1);
for icore = 1:ncores
if(sum(rns) ~= Nr)
rns(icore) = rns(icore)+1;
end
end
RNS(1) = rns(1);
for icore = 2:ncores
RNS(icore) = RNS(icore-1)+rns(icore);
end
rfs = rs(RNS);
r0s = zeros(ncores,1);
r0s(2:end) = rfs(1:end-1);
j = createJob(cluster);
for icore = 1:ncores
r0 = r0s(icore);
rf = rfs(icore);
rn = rns(icore);
trs = linspace(r0, rf, rn);
t{icore} = createTask(j, @int3d_ser, 1, {r0, rf, rn});
end
submit(j);
wait(j);
fints = fetchOutputs(j);
fint = 0.0;
for ifint = 1:length(fints)
fint = fint + fints{ifint};
end
end
我注意到它要快得多。为什么以批处理模式进行此集成与在 parfor
中进行集成不同?
作为参考,我使用 N
测试代码,从 10 和 20(以获取 运行 时间的多项式近似中的常数)到 1000 和 2000 等较大数字。该算法将三次缩放,因为我将 theta
和 phi
方向上的积分节点数指定为给定 N
.
对于 2000 个节点,parfor
版本大约需要 630 秒,而批处理模式下相同数量的节点大约需要 19 秒(其中大约 12 秒只是开销通信,我们也获得了 10 集成节点)。
在与 Mathworks
支持人员交谈后,我似乎对 parfor
的工作原理存在根本性的误解。我的印象是 parfor
表现得像 openMP
,而批处理模式在共享内存和分布式内存方面表现得像 mpi
。
原来parfor
其实也用到了分布式内存。当我创建 4 个批处理函数时,创建新进程的开销发生了 4 次。我认为使用 parfor
会导致该开销仅发生 1 次,然后 parfor
将在同一内存 space 中发生。事实并非如此。
在我的示例代码中,事实证明,对于 parfor
的每次迭代,我实际上都在承担创建新线程的开销。比较 'apples to apples' 时,我实际上应该创建与 parfor
循环中的迭代相同数量的批处理调用。这就是 parfor
函数花费如此长的时间的原因 - 我为多处理招致了 很多 的开销。