2009-11-04 18 views
6

W celu refaktoryzacji mojego kodu MATLAB, myślałem, że będę przekazywał funkcje jako argumenty (co MATLAB nazywa anonimowymi funkcjami), inspirowane funkcjonalnym programowaniem.Powolna wydajność przy użyciu anonimowych funkcji w MATLAB ... czy inni to zauważyli?

Wydaje się jednak, że wydajność została uderzona dość poważnie. W poniższych przykładach porównuję różne podejścia. (Fragment kodu jest zawijany w funkcję, aby móc korzystać z podfunkcji).

Otrzymany wynik to 0 sekund dla bezpośredniego, prawie 0 sekund przy użyciu podfunkcji i 5 sekund przy użyciu anonimowych funkcji. Używam MATLAB 7.7 (R2007b) na OS X 10.6, na C2D 1,8 GHz.

Czy każdy może uruchomić kod i zobaczyć, co otrzyma? Szczególnie interesuje mnie wydajność w systemie 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

Co jest dokładnie Twoje pytanie ?? – Amro

+0

Zastanawiam się, dlaczego i tak robisz takie zbyt skomplikowane obliczenia ... możesz zastąpić potrzebę pętli for za pomocą operacji wektorowych. Na przykład 'y = x.^2;' wyrówna każdy element 'x' i zapisze wynikowy wektor w' y'. – gnovice

+1

FYI: podobne pytanie na temat skuteczności metody OOP: http://stackoverflow.com/questions/1693429/matlab-oop-is-it-slow- or-am-i-doing-something-wrong/1745686#1745686 –

Odpowiedz

15

Oszukujesz z funkcją zagnieżdżoną. :) Funkcja anonimowa jest wywoływana wewnątrz pętli, więc mierzysz koszt wywołania jej 100 000 razy. Funkcja zagnieżdżona jest wywoływana tylko raz, więc jej wezwanie wywołania funkcji jest pomijalne. Aby porównać koszt wywołania funkcji anonimowych i nazwanych, powinieneś mieć funkcję zagnieżdżoną wykonać tę samą pracę co funkcja anonimowa, a następnie wywołać ją z pętli.

Zrobiłem to i wciąż mam podobne wyniki. Anonimowa funkcja jest około 20 razy wolniejsza.

Jednak nadal można używać uchwytów funkcji z funkcjami nieanonimowymi, które nie mają takiego samego działania jak anonimowe funkcje. Działa to z funkcjami zagnieżdżonymi (jak w przypadku foo w oryginalnym teście) lub pod-zagnieżdżonymi podfunkcje (które nie działają jako zamknięcia i mogą mieć mniej narzutów).

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 

Dostaję to na R2009b w systemie Windows.

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

Innym sposobem na to patrzeć jest zorganizować swój kod tak, że to „wektorowy” i działa na macierzach, zmniejszenie liczby wywołań funkcji i koszt wywołania funkcji nie ma znaczenia tak dużo. Byłoby to bardziej idiomatyczne Matlab: typowe porady dotyczące wydajności to ignorowanie kosztów wywołań funkcji i pętli, ponieważ i tak powinieneś wykonywać mniej połączeń na większych argumentach.

+0

Drobna literówka: W twoim kodzie, to, co nazywasz "podfunkcją", jest w rzeczywistości twoją funkcją zagnieżdżoną, i to, co nazywasz "funkcją lokalną" "to właściwie podfunkcja. – gnovice

+1

Edytowane w celu użycia poprawnej terminologii wskazanej przez gnovice; "podfunkcja" jest teraz. –

+0

Tak, masz rację - Oszukuję. Nie celowo jednak ;-) Obecnie przyzwyczajam się do wektoryzacji mojego kodu, np. omijając pętle for i zamiast robić rzeczy takie jak A (A <0) = 0. Ale nie widzę, jak używanie anonimowych funkcji koreluje z idiomami Matlaba - może powinienem po prostu unikać ich używania? – Grav

1

Wyniki komputerze z systemem Windows, Matlab 2009a

>> test 

ans = 

    0 0.0156 1.1094 
1

mogę potwierdzić swoje spostrzeżenia grawitacyjnych. Funkcja speedtest zwraca następujące informacje na moim komputerze.

>> speedtest() 
ans = 
     0 0.0313 1.3906 

Jako przykład, funkcja cputime nie jest najlepszą metodą pomiaru czasu obliczeń. Zamiast tego użyj funkcji tic i toc. see link Te funkcje zapewniają znacznie wyższą rozdzielczość czasową, a za ich pomocą uzyskuję następujące.

>> speedtest() 
ans = 
     0.0062 0.0162 1.3495 
1

Napotkałem ten sam problem co Gary, tylko pomyślałem, że dobrze byłoby sprawdzić odpowiedź Andrew na nowszą wersję Matlab (2014a) (Mac).Pierwsze wyniki:

direct: 0.0722 
anonymous: 0.3916 
subfunction: 0.2277 

a kod użyłem:

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 
Powiązane problemy