6

为了重构我的 MATLAB 代码,我想我会在函数式编程的启发下将函数作为参数传递(MATLAB 称之为匿名函数)。

但是,似乎性能受到了相当严重的打击。在下面的示例中,我比较了不同的方法。(代码片段被包装在一个函数中,以便能够使用子函数)

我得到的结果是直接 0 秒,使用子函数几乎 0 秒,使用匿名函数 5 秒。我在 OS X 10.6、C2D 1.8 GHz 上运行 MATLAB 7.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 次的成本。嵌套函数只被调用一次,因此它的函数调用开销可以忽略不计。为了比较调用匿名函数和命名函数的成本,您应该让嵌套函数做与匿名函数相同的工作,然后也从循环内部调用它。

我这样做了,仍然得到了类似的结果。匿名函数大约慢了 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
    子功能句柄:0.0313
             匿名:1.2344

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

于 2009-11-04T15:11:02.417 回答
1

来自 Windows 机器的结果,Matlab 2009a

>> 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 回答