2009-11-04 8 views
6

Para refactorizar mi código MATLAB, pensé en pasar las funciones como argumentos (lo que MATLAB llama funciones anónimas), inspiradas en la programación funcional.Rendimiento bajo usando funciones anónimas en MATLAB ... ¿otros han notado esto?

Sin embargo, parece que el rendimiento se ve afectado severamente. En los ejemplos a continuación, comparo diferentes enfoques. (El fragmento de código está envuelto en una función para poder usar las subfunciones)

El resultado que obtengo es 0 segundos para directo, casi 0 segundos usando una subfunción, y 5 segundos usando funciones anónimas. Estoy ejecutando MATLAB 7.7 (R2007b) en OS X 10.6, en C2D 1.8 GHz.

¿Alguien puede ejecutar el código y ver qué obtienen? Estoy especialmente interesado en el rendimiento en 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 
+0

Cuál es su pregunta exactamente ?? – Amro

+0

Me pregunto por qué estás haciendo cálculos tan complicados de todos modos ... puedes reemplazar la necesidad de un ciclo for mediante el uso de operaciones vectoriales. Por ejemplo, 'y = x.^2;' cuadrará cada elemento de 'x' y guardará el vector resultante en' y'. – gnovice

+1

FYI: pregunta similar sobre el rendimiento del despacho del método OOP: http://stackoverflow.com/questions/1693429/matlab-oop-is-it-slow-or-am-i-doing-something-wrong/1745686#1745686 –

Respuesta

15

Estás haciendo trampa con la función anidada. :) La función anónima se llama dentro de un bucle, por lo que está midiendo el costo de llamarlo 100.000 veces. La función anidada solo se llama una vez, por lo que su sobrecarga de llamada de función es insignificante. Para comparar el costo de llamar funciones anónimas vs nombradas, debe hacer que la función anidada haga el mismo trabajo que la función anónima y luego llamarla desde dentro de un bucle también.

Lo hice y todavía obtuve resultados similares. La función anónima es aproximadamente 20 veces más lenta.

Sin embargo, aún puede utilizar identificadores de funciones con funciones no anónimas, y que no tienen el mismo rendimiento que las funciones anónimas. Esto funciona con funciones anidadas (como con el foo en su prueba original) o subfunciones no anidadas (que no actúan como cierres y pueden tener menos sobrecarga).

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 

me sale esto en R2009b en Windows.

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

Otra forma de verlo es que la estructura de su código por lo que es "vectorizada" y opera con matrices, lo que reduce el número de llamadas a la función y el costo de la llamada de función no importa tanto. Eso sería más idiomático. Matlab: el consejo típico sobre el rendimiento es ignorar el costo de las llamadas a funciones y los bucles porque, de todos modos, debería hacer menos llamadas en argumentos más grandes.

+0

Error menor: en su código, lo que usted llama una "subfunción" es en realidad su función anidada, y lo que usted llama su "función local" "es en realidad la subfunción. – gnovice

+1

Editado para usar la terminología correcta como lo señala gnovice; "subfunción" es en este momento. –

+0

Sí, tienes razón, estoy haciendo trampa. No a propósito ;-) Actualmente me estoy acostumbrando a vectorizar mi código, ej. evitando for-loops y en su lugar haciendo cosas como A (A <0) = 0. Pero no veo cómo el uso de las funciones anónimas se correlaciona con las expresiones idiomáticas de Matlab, ¿quizás debería simplemente evitar usarlas? – Grav

1

Los resultados de una máquina Windows, Matlab 2009a

>> test 

ans = 

    0 0.0156 1.1094 
1

puedo confirmar sus hallazgos Grav. La función speedtest devuelve lo siguiente en mi computadora.

>> speedtest() 
ans = 
     0 0.0313 1.3906 

Como anotación al margen, el cputime función no es el mejor método para medir el tiempo de cálculo. Use las funciones tic y toc en su lugar. see link Estas funciones proporcionan una resolución de tiempo mucho mayor, y al usarlas obtengo lo siguiente.

>> speedtest() 
ans = 
     0.0062 0.0162 1.3495 
1

Me enfrenté al mismo problema que Gary, pensé que sería bueno comprobar la respuesta de Andrew en una versión más reciente de Matlab (2014a) (Mac).Los resultados más importantes primero:

direct: 0.0722 
anonymous: 0.3916 
subfunction: 0.2277 

y el código utilicé:

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