6

मैं रियल वर्ल्ड ओकैमल (आरडब्ल्यूओ) के अध्याय 8 में ज्ञापन पर अनुभाग को समझने की कोशिश कर रहा हूं। मुझे यह नहीं मिल रहा था, इसलिए मैंने ओकैमल कोड को पायथन में अनुवाद करने का निर्णय लिया। यह अभ्यास उपयोगी साबित हुआ, क्योंकि (1) मैंने अंततः समझ लिया कि आरडब्ल्यूओ क्या कह रहा था, और (2) मैंने कुछ तेज़ पायथन कोड लिखा जो काम करता है। हालांकि, पायथन कोड लिखने में, मैंने दो अलग-अलग तरीकों को याद करने की कोशिश की: एक बार एक रैपिंग फ़ंक्शन को सादा कॉल का उपयोग करके और एक बार पाइथन के सजावटी वाक्यविन्यास का उपयोग करके।पाइथन के सजावटी वाक्यविन्यास सादे रैपर सिंटैक्स की तुलना में तेज़ ज्ञापन कोड क्यों देते हैं?

मैंने फिबोनाची फ़ंक्शन को तीन अलग-अलग तरीकों से याद किया और माप लिया कि प्रत्येक ने 32 जीबी फिबोनैकी संख्या को मेरे 2.9 गीगाहर्ट्ज इंटेल कोर i7 मैकबुक प्रो पर 8 जीबी रैम और ओएस 10.9.2 के साथ दो बार पाइथन 2.7 चलाते हुए गणना की। यह मैं एक आश्चर्यजनक परिणाम दे दी है:

  1. नहीं Memoization बिल्कुल: 2 रों
  2. नियमित Memoization: 1 रों
  3. RWO शैली परस्पर पुनरावर्ती Memoization सादा सिंटैक्स का उपयोग: 2 रों
  4. RWO शैली परस्पर पुनरावर्ती Memoization का उपयोग कर डेकोरेटर वाक्य रचना: कहने के लिए

सब कुछ मैं पढ़ा है का कहना है कि डेकोरेटर वाक्य रचना वास्तव में सिर्फ वाक्यात्मक चीनी है 0.0001 रों:

memoFib = memoize(Fib)

तो # 4 से # 4 इतना तेज़ क्यों है?

from time import time 

def unfib(n): 
    '''Unmemoized Fibonacci''' 
    if n <= 1: return 1 
    else: return unfib(n-1) + unfib(n-2) 

def memoize(f): 
    '''A simple memoization function''' 
    hash = {} 
    def memo_f(x): 
     if not hash.has_key(x): 
      res = f(x) 
      hash[x] = res 
     return hash[x] 
    return memo_f 

# Simple approach to memorizing Fibonacci (#2 from the list above) 
memoFib1 = memoize(unfib) 

# Simple approach to timing functions 
def timeit(its,f,arg): 
    zero = time() 
    for i in range(its): 
     res = f(arg) 
    one = time() 
    print res, one - zero 

# A non-recursive form of Fibonacci 
# that expects the remainder of the 
# function to be passed as an argument. 
# Together, they make a pair of mutually 
# recursive functions. Real World Ocaml 
# refers to this as 'tying the recursive 
# knot' (Ch. 8, Imperative programming). 
def fib_norec(fib,x): 
    if x <= 1: return 1 
    else: return fib(x-1) + fib(x-2) 

def memo_rec(f_norec): 
    '''A memoizing version of make_rec, 
    but using the plain wrapper 
    syntax of the memoize function''' 
    def f(x): 
     return f_norec(f,x) 
    return memoize(f) 

# #3 from list above: memoized using plain call to wrapping function 
memoFib2 = memo_rec(fib_norec) 

def memo_rec2(f_norec): 
    '''A second memoizing version of 
    make_rec (from RWO), but using 
    the decorator syntax''' 
    @memoize 
    def f(x): 
     return f_norec(f,x) 
    return f 

# #4 from list above, memoized using decorator syntax 
memoFib3 = memo_rec2(fib_norec) 

print 'no memo\t\t\t\t\t', 
timeit(2,unfib,32) 
print 'basic memo\t\t\t\t', 
timeit(2,memoFib1,32) 
print 'mutually recursive memo, plain wrapper syntax', 
timeit(2,memoFib2,32) 
print 'mutually recursive memo, decorator syntax', 
timeit(2,memoFib3,32) 

उत्तर

5
def f(x): 
    return f_norec(f,x) 
return memoize(f) 

यहाँ, लौटे समारोह memoized द्वारा उत्पादित एक है, लेकिन स्थानीय नामf अभी भी गैर-memoized समारोह ऊपर स्निपेट में परिभाषित किया है, इसलिए पुनरावर्ती कॉल में से कोई भी लाभ के लिए संदर्भित करता है यादों से। कॉल ग्राफ इस प्रकार है:

<memoized f> 
    f 
    f_noref 
     f 
     f_norec 
      ... 

दूसरी ओर यहाँ,

@memoize 
def f(x): 
    return f_norec(f,x) 
return f 

स्थानीय नामf, memoized समारोह को संदर्भित करता है, ताकि आप इस तरह एक फोन ग्राफ मिलती है:

<memoized f> 
    f 
    f_norec 
     <memoized f> 
     f 
      f_norec 
      <memoized f> 
       ... 

(यह अधिक कॉल की तरह दिखता है, और यह है। मैं प्रति स्तर दो रिकर्सिव कॉलों में से पहला दिखाता हूं, इसलिए आप नहीं देखते कि ज्ञापन कैसे ization दूसरे को छोटा।)

आप मैन्युअल रूप से लिखा था अगर वह डेकोरेटर वाक्य रचना वास्तव में (f = memoize(f); return f) को desugars, तो आप समान व्यवहार और प्रदर्शन देखना चाहते हैं।

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