Kodunuzun diğer sürümlerini çalıştırarak fikri edinebilirsiniz. Döngünüzde bir işlev kullanmak yerine, hesaplamaları açıkça yazmayı düşünün
tic
Soln3 = ones(T, N);
for t = 1:T
for n = 1:N
Soln3(t, n) = 3*x(t, n)^2 + 2*x(t, n) - 1;
end
end
toc
Bilgisayarımda hesaplama süresi:
Soln1 1.158446 seconds.
Soln2 10.392475 seconds.
Soln3 0.239023 seconds.
Oli 0.010672 seconds.
Şimdi, tamamen 'vektörleştirilmiş' çözüm açıkça en hızlısı olsa da, her x girişi için çağrılacak bir işlevi tanımlamanın çok büyük bir ek yük olduğunu görebilirsiniz. Sadece hesaplamayı açıkça yazmak bize 5 faktör hız artışı sağladı. Sanırım bu MATLABs JIT derleyicisinin satır içi işlevleri desteklemediğini gösteriyor . Orada gnovice'nin cevabına göre, anonim bir işlev yerine normal bir işlev yazmak aslında daha iyidir. Dene.
Sonraki adım - iç döngüyü kaldırın (vektörleştirin):
tic
Soln4 = ones(T, N);
for t = 1:T
Soln4(t, :) = 3*x(t, :).^2 + 2*x(t, :) - 1;
end
toc
Soln4 0.053926 seconds.
Başka bir faktör 5 hızlanma: Bu ifadelerde MATLAB'da döngülerden kaçınmanız gerektiğini söyleyen bir şey var ... Yoksa gerçekten var mı? Şuna bir bak o zaman
tic
Soln5 = ones(T, N);
for n = 1:N
Soln5(:, n) = 3*x(:, n).^2 + 2*x(:, n) - 1;
end
toc
Soln5 0.013875 seconds.
'Tam' vektörleştirilmiş sürüme çok daha yakın. Matlab, matrisleri sütun olarak depolar. Her zaman (mümkün olduğunda) hesaplamalarınızı 'sütun bazında' vektörleştirilecek şekilde yapılandırmalısınız.
Şimdi Soln3'e geri dönebiliriz. Döngü sırası 'satır bazında'. Hadi değiştirelim
tic
Soln6 = ones(T, N);
for n = 1:N
for t = 1:T
Soln6(t, n) = 3*x(t, n)^2 + 2*x(t, n) - 1;
end
end
toc
Soln6 0.201661 seconds.
Daha iyi, ama yine de çok kötü. Tek döngü - iyi. Çift döngü - kötü. Sanırım MATLAB, döngülerin performansını iyileştirmek için bazı iyi çalışmalar yaptı, ancak yine de döngü ek yükü var. İçeride daha ağır bir işiniz olsaydı, fark etmezdiniz. Ancak bu hesaplama bellek bant genişliğine bağlı olduğundan, döngü ek yükünü görüyorsunuz. Ve edecek daha da net orada FUNC1 çağıran ek yükünü bakın.
Öyleyse arrayfun'dan ne haber? Orada da işlev yok, bu yüzden çok fazla ek yük var. Ama neden çift iç içe bir döngüden çok daha kötü? Aslında, cellfun / arrayfun kullanma konusu birçok kez kapsamlı olarak tartışılmıştır (örneğin burada , burada , burada ve burada ). Bu işlevler yavaştır, bu tür ince taneli hesaplamalar için bunları kullanamazsınız. Bunları kod kısalığı ve hücreler ile diziler arasında süslü dönüşümler için kullanabilirsiniz. Ancak işlevin yazdığınızdan daha ağır olması gerekir:
tic
Soln7 = arrayfun(@(a)(3*x(:,a).^2 + 2*x(:,a) - 1), 1:N, 'UniformOutput', false);
toc
Soln7 0.016786 seconds.
Soln7'nin artık bir hücre olduğuna dikkat edin .. bazen bu yararlıdır. Kod performansı şimdi oldukça iyi ve çıktı olarak hücreye ihtiyacınız varsa, tamamen vektörleştirilmiş çözümü kullandıktan sonra matrisinizi dönüştürmenize gerek yok.
Öyleyse neden arrayfun basit bir döngü yapısından daha yavaş? Maalesef, kaynak kodu olmadığı için kesin olarak söylemek mümkün değil. Sadece arrayfun'un her türden farklı veri yapısını ve argümanı işleyen genel amaçlı bir işlev olduğundan, doğrudan döngü yuvaları olarak ifade edebileceğiniz basit durumlarda mutlaka çok hızlı olmayacağını tahmin edebilirsiniz. Ek yükün nereden geldiğini bilemeyiz. Daha iyi bir uygulama ile genel giderler önlenebilir mi? Belki değil. Ancak maalesef yapabileceğimiz tek şey, iyi çalıştığı ve çalışmadığı durumları belirlemek için performansı incelemek.
Güncelleme Bu testin yürütme süresi kısa olduğundan, güvenilir sonuçlar elde etmek için şimdi testlerin etrafına bir döngü ekledim:
for i=1:1000
% compute
end
Aşağıda verilen bazı zamanlar:
Soln5 8.192912 seconds.
Soln7 13.419675 seconds.
Oli 8.089113 seconds.
Görüyorsunuz ki dizifun hala kötü, ama en azından üç kat daha kötü değil. Öte yandan, sütun bazlı hesaplamalara sahip tek bir döngü, tamamen vektörleştirilmiş sürüm kadar hızlıdır ... Hepsi tek bir CPU üzerinde yapıldı. Soln5 ve Soln7 sonuçları, 2 çekirdeğe geçersem değişmez - Soln5'te paralel hale getirmek için bir parfor kullanmam gerekir. Hızlanmayı unutun ... Soln7 paralel olarak çalışmaz çünkü arrayfun paralel çalışmaz. Olis vektörize edilmiş versiyonu ise:
Oli 5.508085 seconds.