मैंने एक मामूली रिफैक्टरिंग से एक अजीब प्रदर्शन हिट देखा जो एक लूप को max
पर रिकर्सिव फ़ंक्शन के अंदर कॉल के साथ बदल देता है।अधिकतम (पुनरावर्तनीय) बराबर लूप की तुलना में बहुत धीमा क्यों करता है?
यहाँ सबसे सरल प्रजनन है मैं उत्पादन कर सकता है: मानक प्रत्यावर्तन का उपयोग कर दोनों f1
और f2
calculate भाज्य
import time
def f1(n):
if n <= 1:
return 1
best = 0
for k in (1, 2):
current = f1(n-k)*n
if current > best:
best = current
return best
def f2(n):
if n <= 1:
return 1
return max(f2(n-k)*n for k in (1, 2))
t = time.perf_counter()
result1 = f1(30)
print('loop:', time.perf_counter() - t) # 0.45 sec
t = time.perf_counter()
result2 = f2(30)
print('max:', time.perf_counter() - t) # 1.02 sec
assert result1 == result2
लेकिन में जोड़ा एक अनावश्यक अधिकतम के साथ (सिर्फ इसलिए मैं एक प्रत्यावर्तन में max
उपयोग करने के लिए मिलता है, जबकि अभी भी रखने रिकर्सन सरल):
# pseudocode
factorial(0) = 1
factorial(1) = 1
factorial(n) = max(factorial(n-1)*n, factorial(n-2)*n)
यह ज्ञापन के बिना कार्यान्वित किया गया है, इसलिए कॉल की घातीय संख्या है।
max(iterable)
के साथ कार्यान्वयन लूप के साथ एक से दो गुना धीमा है।
विचित्र रूप से,
(संपादित करें: कभी भी ध्यान न दें, @TimPeters उत्तर देखें) का प्रदर्शन नहीं किया। इसके अलावा, अगर मैं max
बनाम लूप की सीधी तुलना प्रभाव
max(iterable)
के बजाय max(a, b)
का उपयोग करता हूं तो प्रदर्शन विसंगति गायब हो जाती है।
इस प्रदर्शन अंतर को जनरेटर अभिव्यक्ति के साथ करना है जिसे आपने 'अधिकतम':' अधिकतम (f2 (nk) * n में k (1, 2) के लिए पास किया है। जेनरेटर स्पेस ऑप्टिमाइज़ेशन की बात करते समय अच्छा प्रदर्शन करते हैं और गति के मामले में खराब। जेनरेटर को पूरी तरह समाप्त होने तक रोकना और जारी रखना होगा। यह रोक/फिर से शुरू करना एक बड़ा प्रदर्शन हिट है। – direprobs
@MosesKoledoye समस्या यह है कि यह मशीन के लिए अलग-अलग फॉर्म मशीन हो सकती है। आम तौर पर, जेनरेटर धीमे होने लगते हैं, उन्हें रोकना पड़ता है और फिर अपनी नौकरियों को फिर से शुरू करना पड़ता है। – direprobs
@direprobs किसी भी तरह से, 'अधिकतम' संस्करण अभी भी जेन के बिना भी कम है। –