8

aşağıdaki işlevi göz önünde bulundurun:Gereksiz tahsisler

x = rand(30,30,100000) 
b = rand(100000) 
@time mytest(x,b) 

elapsed time: 0.571765222 seconds (727837732 bytes allocated, 66.49% gc time) 

neden bu kadar fazla bellek ve harcama çok fazla zaman ayırdığından: Onu çalıştırdığınızda

function mytest(x, b) 
    y = zeros(x[:,:,1]) 
    for i in 1:length(b) 
     y += b[i] * x[:,:,i] 
    end 
    return y 
end 

, aşağıdaki alıyorum çöp toplama yapıyor? Kod, kararlı olmalı ve += operatörünün yeniden ayırma gerçekleştirmemesini beklerdim. Ancak, her zaman iki matris eklediğinde yeniden tahsis ediyor gibi görünüyor.

Julia'da bir hata olduğunu düşünmeli miyim? Ve daha önemlisi, bu kodu yeniden tahsis etmeyecek şekilde nasıl yazabilirim?

DÜZENLEME: düzeltildi.

+1

Sağ taraf 'b [i] * x [:,:, i]', önce ürünün sol tarafına eklenmeden önce ürünün sonucu ile geçici bir dizi ayırır. Geçici dizinin daha sonra çöp toplanması gerekiyor. En azından ... işte bu yüzden [tag: numpy] ile çalışır. –

+3

@moarningsun, bahşiş için teşekkürler. Performansa ilişkin kritik kodla ilgili önceki deneyimim çoğunlukla bir dilim alırken geçici olarak ayrılmayacak olan C++ ve Eigen kullanıyor. Kodumu döngüler için üç yuvaya sahip olacak şekilde değiştirdim ve ayırma sorunu giderildi. (Bundan önce ArrayViews paketini kullanmayı denedim, ancak bu, işleri düzeltmek için görünmüyordu.) Daha iyi bir yol varsa merak ediyorum. –

+1

@JimGarrison: tartışmaya bakın [burada] (https://groups.google.com/forum/#!topic/julia-users/i5hfGpWRHlk). '+ =' sadece sözdizimsel şekerdir (şimdilik en azından) ve bu yüzden her zaman yeniden tahsis eder (ama birileri yanılıyorsa lütfen beni düzeltin). Ayrıca, üç döngünün probleminizi nasıl çözdüğünü görmek isterim. – cd98

cevap

4

@ cd98, ayırma sorununu çözen üç yuvalı çözümümüzü istedi, ancak eşdeğer bir vektörleştirilmiş sürümden düşük performans göstereceğini tahmin ediyorum. İşte burada:

function mytest(x, b) 
    d1, d2, d3 = size(x) 
    y = zeros(eltype(x), d1, d2) 
    for i in 1:d3 
     for j in 1:d2 
      for k in 1:d1 
       y[k,j] += b[i] * x[k,j,i] 
      end 
     end 
    end 
    return y 
end 

x = rand(30,30,100000) 
b = rand(100000) 
@time mytest(x,b) 
@time mytest(x,b) 

Ve çıkışı:

elapsed time: 0.218220119 seconds (767172 bytes allocated) 
elapsed time: 0.197181799 seconds (7400 bytes allocated) 
3

Base.Cartesian kullanma imkanı da vardır: using Base.Cartesian sonra, sen

@nloops 3 i x begin 
    (@nref 2 y i) += b[i_3] * (@nref 3 x i) 
end 

aynı temelde genişler hangi yazabilir Jim'in cevabı gibi döngüler.

+1

Ama şahsen, bunun çirkin olduğunu düşünüyorum ve Jim'in çözümünü tercih ediyorum. – user4235730

4

(orijinal) tahsis sorunu çözmek yapmaz, ama ben sadece @inbounds ile ikinci çözeltide döngüler sararak bir 1.8x speedup hakkında olsun:

function mytest_inbounds(x, b) 
    d1, d2, d3 = size(x) 
    y = zeros(eltype(x), d1, d2) 
    @inbounds begin 
     for i in 1:d3 
      for j in 1:d2 
       for k in 1:d1 
        y[k,j] += b[i] * x[k,j,i] 
       end 
      end 
     end 
    end 
    return y 
end 

x = rand(30, 30, 100000) 
b = rand(100000) 
@time mytest(x, b) 
@time mytest(x, b) 
@time mytest_inbounds(x, b) 
@time mytest_inbounds(x, b) 

Çıktı:

elapsed time: 0.39144919 seconds (767212 bytes allocated) 
elapsed time: 0.353495867 seconds (7400 bytes allocated) 
elapsed time: 0.202614643 seconds (396972 bytes allocated) 
elapsed time: 0.193425902 seconds (7400 bytes allocated) 

Ayrıca burada ilgili konularda iyi bir tartışma sürü:

https://groups.google.com/forum/#!msg/julia-users/aYS_AvKqPCI/DyTiq4lKIAoJ

İlgili konular