आप अपने कोड के अन्य संस्करणों को चलाकर विचार प्राप्त कर सकते हैं। अपने लूप में एक फ़ंक्शन का उपयोग करने के बजाय, गणनाओं को स्पष्ट रूप से लिखने पर विचार करें
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
मेरे कंप्यूटर पर गणना करने का समय:
Soln1 1.158446 seconds.
Soln2 10.392475 seconds.
Soln3 0.239023 seconds.
Oli 0.010672 seconds.
अब, जबकि पूरी तरह से 'सदिश' समाधान स्पष्ट रूप से सबसे तेज़ है, आप देख सकते हैं कि प्रत्येक x प्रविष्टि के लिए बुलाए जाने वाले फ़ंक्शन को परिभाषित करना एक बहुत बड़ा ओवरहेड है। बस स्पष्ट रूप से गणना लिखने से हमें कारक 5 स्पीडअप मिला। मुझे लगता है कि यह दिखाता है कि MATLABs JIT संकलक इनलाइन फ़ंक्शन का समर्थन नहीं करता है । वहाँ gnovice द्वारा जवाब के अनुसार, यह वास्तव में एक अनाम एक के बजाय एक सामान्य कार्य लिखने के लिए बेहतर है। कोशिश करो।
अगला चरण - आंतरिक लूप को हटाएं (वेक्टर करें):
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.
एक अन्य कारक 5 स्पीडअप: उन बयानों में कुछ ऐसा है जो आपको MATLAB में लूप से बचना चाहिए ... या क्या वास्तव में है? इस पर एक नजर है
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.
'पूरी तरह से' सदिश संस्करण के करीब। Matlab कॉलम कॉलम-वार को संग्रहीत करता है। आपको हमेशा (जब संभव हो) अपने कम्प्यूटेशंस को 'कॉलम-वार' करने के लिए तैयार करना चाहिए।
अब हम वापस सोलन 3 जा सकते हैं। लूप ऑर्डर 'पंक्ति-वार' है। इसे बदलने की सुविधा देता है
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.
बेहतर है, लेकिन अभी भी बहुत खराब है। सिंगल लूप - अच्छा। डबल लूप - खराब। मुझे लगता है कि MATLAB ने लूप के प्रदर्शन को बेहतर बनाने के लिए कुछ अच्छे काम किए, लेकिन फिर भी लूप ओवरहेड है। यदि आपके अंदर कुछ भारी काम होगा, तो आप ध्यान नहीं देंगे। लेकिन चूंकि यह गणना मेमोरी बैंडविड्थ से बंधी है, आप लूप ओवरहेड देखते हैं। और आप और भी स्पष्ट रूप से वहाँ Func1 कॉलिंग के ओवरहेड देखेंगे।
तो क्या arrayfun के साथ है? कोई फ़ंक्शन इनलाइनिग भी नहीं है, इसलिए बहुत अधिक ओवरहेड। लेकिन एक डबल नेस्टेड लूप से इतना बुरा क्यों? दरअसल, सेलफुन / अरफुन का उपयोग करने के विषय पर कई बार चर्चा की गई है (जैसे यहां , यहां , यहां और यहां )। ये कार्य केवल धीमी गति से होते हैं, आप इनका उपयोग इस तरह के महीन दाने की गणना के लिए नहीं कर सकते हैं। आप उन्हें कोशिकाओं और सरणियों के बीच कोड संक्षिप्तता और फैंसी रूपांतरणों के लिए उपयोग कर सकते हैं। लेकिन फ़ंक्शन को आपके द्वारा लिखे गए से भारी होना चाहिए:
tic
Soln7 = arrayfun(@(a)(3*x(:,a).^2 + 2*x(:,a) - 1), 1:N, 'UniformOutput', false);
toc
Soln7 0.016786 seconds.
ध्यान दें कि Soln7 अब एक सेल है .. कभी-कभी यह उपयोगी है। कोड का प्रदर्शन अब काफी अच्छा है, और यदि आपको आउटपुट के रूप में सेल की आवश्यकता है, तो आपको पूरी तरह से वेक्टर किए गए समाधान का उपयोग करने के बाद अपने मैट्रिक्स को बदलने की आवश्यकता नहीं है।
तो एक साधारण लूप संरचना की तुलना में अरफुन धीमा क्यों है? दुर्भाग्य से, हमारे लिए यह सुनिश्चित करना असंभव है, क्योंकि कोई स्रोत कोड उपलब्ध नहीं है। आप केवल अनुमान लगा सकते हैं कि चूंकि arrayfun एक सामान्य उद्देश्य फ़ंक्शन है, जो सभी प्रकार के विभिन्न डेटा संरचनाओं और तर्कों को संभालता है, यह आवश्यक नहीं है कि सरल मामलों में बहुत तेज़ हो, जिसे आप सीधे लूप घोंसले के रूप में व्यक्त कर सकते हैं। ओवरहेड कहां से आता है हम नहीं जान सकते। क्या बेहतर क्रियान्वयन से ओवरहेड से बचा जा सकता है? शायद नहीं। लेकिन दुर्भाग्य से केवल एक चीज जो हम कर सकते हैं वह है मामलों की पहचान करने के लिए प्रदर्शन का अध्ययन, जिसमें यह अच्छी तरह से काम करता है, और वे, जहां यह नहीं है।
अपडेट करें क्योंकि इस परीक्षण का निष्पादन समय कम है, विश्वसनीय परिणाम प्राप्त करने के लिए मैंने परीक्षणों के चारों ओर एक लूप जोड़ा:
for i=1:1000
% compute
end
नीचे दिए गए कुछ समय:
Soln5 8.192912 seconds.
Soln7 13.419675 seconds.
Oli 8.089113 seconds.
आप देखते हैं कि सरणीफुन अभी भी खराब है, लेकिन कम से कम परिमाण के तीन आदेश वेक्टरकृत समाधान से भी बदतर हैं। दूसरी ओर, स्तंभ-वार संगणना के साथ एक एकल लूप पूरी तरह से सदिश संस्करण के रूप में तेज़ है ... यह सब एक सीपीयू पर किया गया था। Soln5 और Soln7 के लिए परिणाम नहीं बदलते हैं अगर मैं 2 कोर पर स्विच करता हूं - Soln5 में मुझे इसे समानांतर करने के लिए एक parfor का उपयोग करना होगा। स्पीडअप के बारे में भूल जाओ ... Soln7 समानांतर में नहीं चलता है क्योंकि arrayfun समानांतर में नहीं चलता है। दूसरी ओर ओलिस वेक्टरकृत संस्करण:
Oli 5.508085 seconds.