2014-12-28 6 views
7

Julia'da (R veya Matlab'dan farklı olarak), devredilen kodun genellikle vektörel koddan daha hızlı olduğunu düşündüm. Ama ben böyle bir durum bulamadım. İşte bir örnek:Neden bu devectorized Julia kodu 20x fazla yavaş?

julia> x = Float64[1:10000000]; 

julia> y = Array(Float64, length(x)); 

julia> @time for i = 1:length(x) y[i] = exp(x[i]) end; 
elapsed time: 7.014107314 seconds (959983704 bytes allocated, 25.39% gc time) 

julia> @time y = exp(x); 
elapsed time: 0.364695612 seconds (80000128 bytes allocated) 

Vektörel kod neden bu kadar hızlı? Bu, devredilmiş kodun 10 kat fazla bellek ayırdığını gösteriyor. Ancak, sadece birkaç bayt, herhangi bir sayıda floatın katlanması için tahsis edilmelidir. Devredilmiş kodu yazmak için bir yol var mı, böylece çok fazla bellek ayırmıyor ve dolayısıyla vektörel koddan daha hızlı mı çalışıyor?

Teşekkürler!

+0

"_I thought ..._" Bu doğanın iddialarını desteklemek için her zaman bazı kanıtlar sunmalısınız. – csmckelvey

+2

Elbette, Julia'da ne kadar hızlı devredilmiş kodun olabileceğini gösteren bir yayın var: http://www.johnmyleswhite.com/notebook/2013/12/22/the-relationship-between-vectorized-and-devectorized-code/ – Jeff

cevap

10

Aşağıdaki kod parçasını inceleyin: kez

A: elapsed time: 0.072701108 seconds (115508 bytes allocated) 
B: elapsed time: 0.074584697 seconds (80201532 bytes allocated) 
C: elapsed time: 2.029597656 seconds (959990464 bytes allocated, 22.86% gc time) 
D: elapsed time: 0.058509661 seconds (80000128 bytes allocated) 

Farklı olanı verir

x = Float64[1:10000000]; 
y = Array(Float64, length(x)); 
function nonglobal_devec!(x,y) 
    for i = 1:length(x) y[i] = exp(x[i]) end 
end 
function nonglobal_vec(x) 
    exp(x) 
end 
@time nonglobal_devec!(x,y); 
@time y = nonglobal_vec(x); 
x = Float64[1:10000000]; 
y = Array(Float64, length(x)); 
@time for i = 1:length(x) y[i] = exp(x[i]) end 
@time y = exp(x) 

, C, türü çıkarımın çalışmadığı due to it operating in the global scope ve s alt kod üretilir.

A ve B arasındaki göreceli zamanlamalar, ilk kez kullanıldığında derlenmiş olan işlevler nedeniyle bazı değişkenliğe tabidir. onu tekrar dolarsa A2 (80 bayt fonksiyonun dönüş değeri için olduğunu) bellek değil olarak mantıklı ve B2 yeni vektör oluşturur

A2: elapsed time: 0.038542212 seconds (80 bytes allocated) 
B2: elapsed time: 0.063630172 seconds (80000128 bytes allocated) 

olsun. Ayrıca B2'nin D bellekle aynı miktarda bellek ayırdığını da unutmayın - ek olarak ilk kez derleme için ayrılmış bellek. Son olarak, vektöre göre dağıtılan ve duruma göre dağıtılmış durumdur. Örneğin, döngüleri için saf olarak matris çarpma uyguladıysanız ve önbellek farkındalığı yoksa, BLAS kullanan vectorized A*b'u kullanmaktan çok daha yavaş olursunuz.

+2

Teşekkürler, Iain, bu benimkinden çok daha iyi bir cevap. – StefanKarpinski

+0

Bu iş parçacığı, işlev çağrıldığında her defasında A2'de 80 bayt atanmış mı diye sormak için biraz uğraşacağım? Örneğin, bu işlev 10^5 kez çağıran bir döngüde ise, 80 * 10^5 bayt ayrılacak mı? – Nick

+0

Oldukça emin değil, kontrol etmek kolay - onun sadece bir REPL şey. Yine de REPL'de işler garip! Bu komutu bir döngüde (REPL) koyacak olsaydınız, muhtemelen 80 bayt elde edersiniz, bu döngüde son kez gelen değerdir. – IainDunning