我试图加速以下代码:
$json[]=array(
'value'=> $fName,
'label'=> $fName,
'lName'=> $lName,
'tel' => $telNo,
'loc'=> $locs
);
从上面的代码可以看出,我使用了tic toc,我发现每个i值的每个循环迭代如下:
xdim=5560;
ydim=6945;
zdim=7;
Nexi=270250785;
Neyi=270260480;
kne=1;
for i=1:xdim
tic
for j=1:ydim
for k=1:zdim
if j<ydim
map_ey(j+(k-1)*(ydim-1)+(i-1)*(ydim-1)*zdim+Nexi)=kne;
kne=kne+1;
end
end
end
for j=1:ydim
for k=1:zdim
if k<zdim
map_ez(j+(k-1)*ydim+(i-1)*ydim*(zdim-1)+Nexi+Neyi)=kne;
kne=kne+1;
end
end
end
for j=1:ydim
for k=1:zdim
if i<xdim
map_ex(j+(k-1)*ydim+(i-1)*ydim*zdim)=kne;
kne=kne+1;
end
end
end
toc
end
可以更快吗?请帮忙。提前谢谢。
答案 0 :(得分:2)
正如您所知,for循环(实现它们的方式)在MATLAB中相对较慢。有时它们是不可避免的,但我们可以做一些简单的事情来尝试优化它们。
首先是查看mlint警告以获取帮助(MATLAB编辑器中的橙色下划线)。如果您注意到,每次进行循环时,您都会扩展map_ex
,map_ey
和map_ez
的大小。这会导致MATLAB不断重新分配用于存储这些变量的内存,这会导致程序随着这些数组的大小增长而变得越来越慢。为了避免这个陷阱,预先分配数组(即在开头创建一个与数组一样大的空数组。)
在您的情况下,这似乎是以下
map_ex = zeros(1, (xdim - 1) * ydim * zdim);
map_ey = zeros(1, (xdim * (ydim - 1) * zdim) + Nexi);
map_ez = zeros(1, (xdim * ydim * (zdim - 1)) + Nexi + Neyi);
然后你可以像你现在写的那样执行你的for循环,你应该注意到一个立即的性能提升。
在查看代码时我注意到的另一件事是你在整个
中重复了这个主题for k=1:zdim
if k < zdim
% Do something
end
end
这里的问题是,您每次循环时都会将k
与zdim
进行比较,而您可以真正只循环k
for k = 1:(zdim - 1)
% Do something
end
这将删除每次循环评估的不必要的if
语句。
我相信你知道,在MATLAB中做事的首选方法是通过矢量化而不是循环。如何以清晰简洁的方式对代码进行矢量化很困难,而不会看到您在此处尝试实现的内容。到目前为止,我可以对你所拥有的内容进行矢量化,但我觉得可能有更好的方法来实现它。如果您可以提供有关您尝试解决的问题的更多信息,也许我可以提供更多帮助。
此外,如果你真的需要性能并且无法避免使用for循环,MATLAB确实提供了mex library,因此你可以在C / C ++中实现这种类型的代码,并且仍然可以在MATLAB中调用它。
答案 1 :(得分:2)
幸运的是,我认为这是programming puzzle,并对您的代码进行了解卷积,尽管您不愿意明确地解释您希望实现的目标。这是一个简短的解决方案,测试尺寸较小:
xdim = 4;
ydim = 5;
zdim = 3;
% avoid magic numbers
Nexi = (xdim-1)*ydim*zdim;
Neyi = xdim*(ydim-1)*zdim;
Nezi = xdim*ydim*(zdim-1);
% preallocate
map_ex2 = zeros(1,Nexi);
map_ey2 = zeros(1,Nexi+Neyi);
map_ez2 = zeros(1,Nexi+Neyi+Nezi);
% index jump between blocks of the same variable
dN = ydim*zdim + (ydim-1)*zdim + (zdim-1)*ydim;
%construct matrices
map_ey2(Nexi+1:Nexi+Neyi) = ...
permute(reshape(bsxfun(@plus,(1:xdim*zdim).',(0:ydim-2)*dN),... %'
[zdim,xdim,ydim-1]),...
[2 1 3]);
map_ez2(Nexi+Neyi+1:Nexi+Neyi+Nezi) = ...
permute(reshape(bsxfun(@plus,(1:(zdim-1)*ydim).'+xdim*zdim,(0:xdim-1)*dN),... %'
[zdim-1,ydim,xdim]),...
[2 1 3]);
map_ex2(1:Nexi) = ...
permute(reshape(bsxfun(@plus,(1:(xdim-1)*ydim).'+xdim*zdim+(zdim-1)*ydim,... %'
(0:zdim-1)*dN),...
[xdim-1,ydim,zdim]),...
[2 1 3]);
运行原始循环版本并检查
isequal(map_ex,map_ex2)
isequal(map_ey,map_ey2)
isequal(map_ez,map_ez2)
告诉我,这应该和你正在做的一样,只是没有任何循环。
如您所见,我定义了动态变量Nexi
,Neyi
,Nezi
以避免使用幻数。我建议您采用这种行为。
上述解决方案确实很混乱,但原来的三重循环也是如此。 @Divakar有可能以这种方式出现并为您提供更优雅/更有效的解决方案;)