8

निम्नलिखित समारोह पर विचार करें:अनावश्यक जूलिया अद्यतन ऑपरेटर्स का उपयोग कर आवंटन

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

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

यह इतना स्मृति और खर्च इतना समय क्यों आवंटित किया गया है:

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

जब मैंने इसे चलाने के लिए, मैं निम्नलिखित मिल कचरा संग्रह कर रहे हैं? कोड स्थिर प्रकार होना चाहिए, और मैं += ऑपरेटर को फिर से आवंटन करने की अपेक्षा करता हूं। हालांकि, ऐसा लगता है कि यह प्रत्येक बार दो मैट्रिक्स जोड़ता है फिर से आवंटित किया जाता है।

क्या मुझे यह जूलिया में एक बग माना जाना चाहिए? और सबसे महत्वपूर्ण बात यह है कि मैं इस कोड को ऐसे तरीके से कैसे लिख सकता हूं जो आवंटित नहीं होता है?

संपादित करें: निश्चित टाइपो।

+1

दायां हाथ की ओर 'बी [i] * x [:,:, i]' पहले उत्पाद के परिणाम के साथ एक अस्थायी सरणी आवंटित करता है इससे पहले कि बाईं ओर स्थित जगह में जोड़ा जाता है। अस्थायी सरणी को तब कचरा इकट्ठा करने की जरूरत है। कम से कम ... इस तरह यह [टैग: numpy] के साथ काम करेगा। –

+3

@moarningsun, टिप के लिए धन्यवाद। प्रदर्शन महत्वपूर्ण कोड के साथ मेरा पिछला अनुभव ज्यादातर सी ++ और ईजिन का उपयोग कर रहा है, जो एक टुकड़ा लेने पर अस्थायी आवंटित नहीं करेगा। मैंने लूप के लिए तीन नेस्टेड रखने के लिए अपना कोड बदल दिया है, और आवंटन समस्या ठीक कर दी गई है। (इससे पहले मैंने ArrayViews पैकेज का उपयोग करने की कोशिश की, लेकिन यह चीजों को ठीक करने के लिए प्रतीत नहीं होता था।) यदि कोई बेहतर तरीका है तो मैं अभी भी उत्सुक हूं। –

+1

@JimGarrison: चर्चा [यहां] देखें (https://groups.google.com/forum/#!topic/julia-users/i5hfGpWRHlk)। '+ =' सिर्फ सिंटैक्टिक चीनी है (अब कम से कम) और इसलिए मुझे लगता है कि यह हमेशा फिर से आवंटित होता है (लेकिन अगर कोई गलत है तो कृपया मुझे सही करें)। साथ ही, मुझे यह देखने में दिलचस्पी होगी कि तीन लूप ने आपकी समस्या का समाधान कैसे किया। – cd98

उत्तर

4

@ cd98 ने मेरे तीन-नेस्टेड-लूप समाधान का अनुरोध किया, जो आवंटन समस्या हल करता है लेकिन मुझे लगता है कि समकक्ष वेक्टरकृत संस्करण को कम प्रदर्शन करना होगा। संदेश यह है:

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) 

और उत्पादन:

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

वहाँ भी Base.Cartesian उपयोग करने की संभावना है: using Base.Cartesian के बाद, आप

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

मूलतः एक ही करने के लिए फैलता है जो लिख सकते हैं जिम के जवाब में लूप।

+1

लेकिन व्यक्तिगत रूप से, मुझे लगता है कि यह बदसूरत है और मैं जिम का समाधान पसंद करता हूं। – user4235730

4

(मूल) आवंटन समस्या का समाधान नहीं करता है, लेकिन मैं एक 1.8x speedup के बारे में बस @inbounds के साथ बाद समाधान में छोरों लपेटकर द्वारा प्राप्त करें:

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) 

आउटपुट:

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) 

इसके अलावा, यहां संबंधित मुद्दों पर अच्छी चर्चा के बहुत सारे:

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

संबंधित मुद्दे