[英]Matlab scalar operation takes longer than array operation
在使用事件探查器加速代碼時,我注意到單個數組元素上的標量運算比整個數組上的矢量化運算花費的時間更長。 顯然,這不是人們所期望的,因為使用數組元素時只有一個操作發生,而對數組進行矢量化操作時會發生許多操作(盡管是矢量化的)。
我看到的上下文有點復雜,標量操作沒有在與數組相同的嵌套對象上完成。 但是,我可以使用腳本來復制這種奇怪之處:
%%%%%%%%%%%%%
%% tst1.m
%%%%%%%%%%%%%
% Generate random data
for ix=1:5; for iy=1:5
x(ix).y(iy).z=rand(1,10);
end; end
Ntest=1e7;
disp('Script tst#1a: Operation on one array element:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z(1);
end % for i
toc
% clear a
disp('Script tst#1b: Vectorized operation on entire array:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z;
end % for i
toc
上面的腳本tst#1a是單個數組元素操作,而腳本tst#1b是整個數組上的矢量化操作。 結果是:
Script tst#1a: Operation on one array element:
Elapsed time is 6.260495 seconds.
Script tst#1b: Vectorized operation on entire array:
Elapsed time is 4.491822 seconds.
可以看出,標量運算花費的時間明顯更長。 有人能推測出這種違反直覺的觀察的原因嗎? 也許測試代碼中確實有些愚蠢的東西?
在組裝上述測試時,我還發現,如果我清除了左側變量,例如在上面注釋的語句中,則標量運算幾乎加速了2倍。我不知道為什么,但是無論出於何種原因,我發現即使在標量操作測試代碼之后進行清除操作,標量操作測試代碼也會加速,這更奇怪。 這是相同的m文件,其中clear命令未注釋:
%%%%%%%%%%%%%
%% tst2.m
%%%%%%%%%%%%%
% Generate random data
for ix=1:5; for iy=1:5
x(ix).y(iy).z=rand(1,10);
end; end
Ntest=1e7;
disp('Script tst#2a: Operation on one array element:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z(1);
end % for i
toc
disp('Clearing a');
clear a
disp('Script tst#2b: Vectorized operation on entire array:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z;
end % for i
toc
這是結果,顯示了前面的標量運算測試代碼的莫名其妙的加速(與tst1.m的結果相比):
Script tst#2a: Operation on one array element:
Elapsed time is 3.371326 seconds.
Clearing a
Script tst#2b: Vectorized operation on entire array:
Elapsed time is 4.463924 seconds.
這些測試都不能完全反映我的情況,我使用類方法而不是腳本。 我記得在一個論壇上讀過一篇文章,該文章與腳本,函數和方法相比,為編譯器優化提供了更多機會。 為了弄清楚這是否可以解釋標量運算的相對緩慢以及事后清除帶來的反直覺的加速,我將上面的兩個測試腳本放入類方法中:
%%%%%%%%%%%%%%
%% cTest.m
%%%%%%%%%%%%%%
classdef cTest < handle
methods
function tst1(o)
% Generate random data
for ix=1:5; for iy=1:5
x(ix).y(iy).z=rand(1,10);
end; end
Ntest=1e7;
disp('Method tst#1a: Operation on one array element:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z(1);
end % for i
toc
% clear a
disp('Method tst#1b: Vectorized operation on entire array:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z;
end % for i
toc
end % function tst1
function tst2(o)
% Generate random data
for ix=1:5; for iy=1:5
x(ix).y(iy).z=rand(1,10);
end; end
Ntest=1e7;
disp('Method tst#2a: Operation on one array element:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z(1);
end % for i
toc
disp('Clearing a');
clear a
disp('Method tst#2b: Vectorized operation on entire array:')
tic
for i=1:Ntest
a=0.5>x(3).y(3).z;
end % for i
toc
end % function tst2
end % method
end % classdef
我使用以下“ testbench”腳本比較上述所有m文件的執行情況:
%%%%%%%%%%%
%% go.m
%%%%%%%%%%%
clc
c = cTest;
tst1
disp(' ')
tst2
fprintf('\n\n')
c.tst1
disp(' ')
c.tst2
合並結果為:
Script tst#1a: Operation on one array element:
Elapsed time is 5.888381 seconds.
Script tst#1b: Vectorized operation on entire array:
Elapsed time is 4.636491 seconds.
Script tst#2a: Operation on one array element:
Elapsed time is 3.435526 seconds.
Clearing a
Script tst#2b: Vectorized operation on entire array:
Elapsed time is 4.531256 seconds.
Method tst#1a: Operation on one array element:
Elapsed time is 5.732293 seconds.
Method tst#1b: Vectorized operation on entire array:
Elapsed time is 4.550085 seconds.
Method tst#2a: Operation on one array element:
Elapsed time is 3.266772 seconds.
Clearing a
Method tst#2b: Vectorized operation on entire array:
Elapsed time is 4.664736 seconds.
在輸出文本的4個塊中,第一個2個塊是上述2個sript測試的重新運行,而最后兩個輸出塊執行相同的代碼,但作為類方法。 結果是相似的,因此標量運算的莫名其妙的緩慢性,以及由於事后清除命令而導致的違反直覺的加速,似乎不受腳本和類方法之間的編譯差異的影響。
綜上所述,
數組元素上的標量運算似乎比數組運算運行速度慢。 也許與從數組中提取單個元素相關的某種速度損失,我並不知道。
事后清除明顯地加快了標量運算的速度,因此它比數組運算更快。 無論是否存在clear命令,這都是期望的。
這些觀察似乎不受腳本和類方法之間任何編譯差異的影響。
如果有人能闡明可能導致上述發現的內部工作原理,也許我可以利用這種見解擺脫類方法中對單個數組元素進行標量運算的緩慢性。
注釋:即使沒有在結構數組的層中深度嵌套數組,也可以觀察到觀察值#1:
>> clear all; x=rand(1,10); tic; for i=1:1e7; a=0.5>x(1); end; toc
Elapsed time is 0.092028 seconds.
>> clear all; x=rand(1,10); tic; for i=1:1e7; a=0.5>x; end; toc
Elapsed time is 1.344769 seconds.
這是在運行64位Windows 7、8GB RAM的3Ghz筆記本電腦上使用的MATLAB版本8.5.0.197613(R2015a),而沒有其他消耗內存的操作。 Matlab使用550GB,Internet Explorer使用240GB。
根據迄今為止的信息,亞歷山大·肯普的答案似乎是可能的解釋。 索引到數組以訪問各個元素似乎要花費大量時間。 標量運算本身可能不比矢量化運算花費更長的時間。 從標量運算的數組中提取元素會導致速度損失。
不知道是什么真正原因,但是我將調查三件事:
編輯:JIT->循環優化
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.