6

MATLABコードをリファクタリングするために、関数型プログラミングに触発された引数(MATLABが無名関数と呼ぶもの)として関数を渡すと思いました。

ただし、パフォーマンスはかなり深刻な打撃を受けているようです。以下の例では、さまざまなアプローチを比較しています。(サブ関数を使用できるようにするために、コードスニペットは関数でラップされています)

私が得た結果は、直接の場合は0秒、サブ関数を使用した場合はほぼ0秒、無名関数を使用した場合は5秒です。私は、OS X 10.6、C2D 1.8GHzでMATLAB7.7(R2007b)を実行しています。

誰かがコードを実行して、何が得られるかを確認できますか?特にWindowsでのパフォーマンスに興味があります。

function [] = speedtest()


clear all; close all;

function y = foo(x)
    y = zeros(1,length(x));
    for j=1:N
        y(j) = x(j)^2;
    end
end

x = linspace(-100,100,100000);
N = length(x);


%% direct
t = cputime;

y = zeros(1,N);
for i=1:N
    y(i) = x(i)^2;
end

r1 = cputime - t;

%% using subfunction
t = cputime;
y = foo(x);
r2 = cputime - t;

%% using anon function
fn = @(x) x^2;

t = cputime;

y = zeros(1,N);
for i=1:N
    y(i) = fn(x(i));
end

r3 = cputime-t;

[r1 r2 r3]

end
4

4 に答える 4

16

入れ子関数で不正行為をしています。:)無名関数はループ内で呼び出されているため、100,000回呼び出すコストを測定しています。ネストされた関数は1回だけ呼び出されるため、関数呼び出しのオーバーヘッドはごくわずかです。匿名関数と名前付き関数を呼び出すコストを比較するには、ネストされた関数に匿名関数と同じ機能を実行させてから、ループ内からも呼び出す必要があります。

私はそれをしましたが、それでも同様の結果が得られました。匿名関数は約20倍遅くなります。

ただし、非匿名関数で関数ハンドルを使用することはできますが、匿名関数と同じパフォーマンスの低下はありません。これは、ネストされた関数(元のテストのfooと同様)またはネストされていないサブ関数(クロージャとして機能せず、オーバーヘッドが少ない可能性があります)のいずれかで機能します。

function [] = speedtest()

function y = foo(x)
    y = x^2;
end

r = struct;

...

%% using nested function through function handle
fn = @foo;
y = zeros(1,N);
t = cputime;
for i=1:N
    y(i) = fn(x(i));
end
r.nested_handle = cputime - t;

...

%% using subfunction through function handle
fn = @subfunction_foo;
y = zeros(1,N);
t = cputime;
for i=1:N
    y(i) = fn(x(i));
end
r.subfunction_handle = cputime - t;

...

end % end function speedtest

function y = subfunction_foo(x)
y = x^2;
end

これはWindowsのR2009bで取得します。

>>スピードテスト
                直接:0
                ネスト:0.0469
         ネストされたハンドル:0.0781
           サブ機能:0.0313
    subfunction_handle:0.0313
             匿名:1.2344

別の見方をすれば、コードを「ベクトル化」して配列で動作するように構造化することで、関数呼び出しの数を減らし、関数呼び出しのコストはそれほど重要ではありません。それはもっと慣用的なMatlabです:とにかく大きな引数でより少ない呼び出しを行うべきなので、典型的なパフォーマンスのアドバイスは関数呼び出しとループのコストを無視することです。

于 2009-11-04T15:11:02.417 に答える
1

Windowsマシン、Matlab2009aの結果

>> test

ans =

     0    0.0156    1.1094
于 2009-11-04T11:53:16.677 に答える
1

私はあなたの発見を確認することができますGrav。speedtest関数は、私のコンピューターで次のように返します。

>> speedtest()
ans =
         0    0.0313    1.3906

補足として、関数cputimeは、計算時間を測定するための最良の方法ではありません。代わりにtic関数とtoc関数を使用してください。リンクを参照 これらの関数ははるかに高い時間分解能を提供し、それらを使用すると次のようになります。

>> speedtest()
ans =
         0.0062    0.0162    1.3495
于 2009-11-04T11:54:51.923 に答える
1

私はGaryと同じ問題に直面しましたが、Matlab(2014a)(Mac)のより新しいバージョンでAndrewの答えを確認するのが良いと思いました。最初の結果:

direct: 0.0722
anonymous: 0.3916
subfunction: 0.2277

そして私が使用したコード:

function []=SpeedTest()

fanon = @(x,y) x*x+y*y;

iter=1000000;
x=1:iter;
y=1:iter;
var1=nan(size(x));
var2=nan(size(x));
var3=nan(size(x));
timefor=struct('direct',nan,'anonymous',nan','subfunction',nan);

tic;
for i=1:iter
    var1(i)=x(i)*x(i)+y(i)*y(i);
end
timefor.direct=toc;

tic;
for i=1:iter
    var2(i)=fanon(x(i),y(i));
end
timefor.anonymous=toc;

tic;
for i=1:iter
    var3(i)=fsub(x(i),y(i));
end
timefor.subfunction=toc;

display(timefor);
end

function [z]=fsub(x,y)
z=x*x+y*y;
end
于 2014-07-20T15:35:30.120 に答える