使用MATLAB中的匿名函数来降低性能...还有其他人注意到这一点吗?

Gra*_*rav 6 performance matlab anonymous-function

为了重构我的MATLAB代码,我认为我将函数作为参数(MATLAB称为匿名函数)传递,受函数式编程的启发.

然而,似乎表现受到严重打击.在下面的例子中,我比较了不同的方法.(代码片段包含在函数中以便能够使用子函数)

我得到的结果是直接0秒,使用子功能几乎0秒,使用匿名函数5秒.我在OS X 10.6上运行MATLAB 7.7(R2007b),在C2D 1.8 GHz上运行.

任何人都可以运行代码,看看他们得到了什么?我对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
Run Code Online (Sandbox Code Playgroud)

And*_*nke 16

你在使用嵌套函数作弊.:)匿名函数在循环内被调用,所以你要测量调用100,000次的成本.嵌套函数只被调用一次,因此其函数调用开销可以忽略不计.要比较调用匿名函数和命名函数的成本,您应该让嵌套函数执行与匿名函数相同的工作,然后从循环内部调用它.

我这样做了,仍然得到了类似的结果.匿名函数慢了大约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
Run Code Online (Sandbox Code Playgroud)

我在Windows上的R2009b上得到了这个.

>> speedtest
                direct: 0
                nested: 0.0469
         nested_handle: 0.0781
           subfunction: 0.0313
    subfunction_handle: 0.0313
             anonymous: 1.2344

另一种看待它的方法是构造你的代码,使其"向量化"并在数组上运行,减少函数调用的次数,并且函数调用的成本并不重要.那将是更惯用的Matlab:典型的性能建议是忽略函数调用和循环的代价,因为无论如何你应该对更大的参数进行更少的调用.

  • @Grav:这不是匿名的非惯用语; 这是一小部分工作.我只是意味着矢量化代码导致更少的函数调用调用,每个函数调用调用都适用于更大的输入数组,这是惯用的Matlab.听起来你走在正确的轨道上.如果方便的话,继续使用anons; 只需使它们像"@(x)x.^ 2"一样进行矢量化,然后性能命中就不那么重要了. (2认同)