Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

Ruby में मेमोइज़ेशन में महारत हासिल करें: सरल कैशिंग तकनीकों से प्रदर्शन बढ़ाएं

आज मैं प्रदर्शन में सुधार के लिए अपनी पसंदीदा तकनीकों में से एक के बारे में बात करना चाहता था। यह आसान छोटे प्रदर्शन जीत का एक स्रोत है जो अंततः जुड़ जाते हैं, और केवल कभी-कभी आपके एप्लिकेशन को धुएं के ढेर में बदल देते हैं। बहुत कभी-कभी।

इस तकनीक को "मेमोइज़ेशन" कहा जाता है। $10 कंप्यूटर-साइंस शब्द के बावजूद, इसका सीधा सा मतलब है कि, हर बार मेथड कॉल करने पर वही काम करने के बजाय, आप रिटर्न वैल्यू को एक वेरिएबल में सेव करते हैं और उसके बजाय उसका उपयोग करते हैं।

यहाँ छद्म कोड में यह कैसा दिखता है:

def my_method
  @memo = <work> if @memo is undefined
  return @memo
end

और यहाँ आप इसे Ruby में कैसे करते हैं। यह सबसे मजबूत दृष्टिकोण है, लेकिन यह काफी वर्बोज़ है। अन्य, अधिक संक्षिप्त दृष्टिकोण हैं जिन पर हम बाद में चर्चा करेंगे।

class MyClass
  def my_method
    unless defined?(@my_method)
      @my_method = begin
        # अपना कैलकुलेशन, डेटाबेस क्वेरी
        # या अन्य लंबे समय तक चलने वाला काम यहां करें।
      end
    end
    @my_method
  end
end

उपरोक्त कोड तीन चीजें करता है:

  1. जांचता है कि क्या @my_method नाम का एक इंस्टेंस वेरिएबल मौजूद है।
  2. यदि है, तो यह कुछ काम करता है और परिणाम को @my_method में सेव करता है।
  3. यह @my_method लौटाता है

इस तथ्य से भ्रमित न हों कि हमारे पास my_method नाम का एक मेथड और एक इंस्टेंस वेरिएबल दोनों हैं। मैं अपने वेरिएबल को कुछ भी नाम दे सकता था, लेकिन मेमोइज़ किए जा रहे मेथड के नाम पर इसका नाम रखना कन्वेंशन है।

एक संक्षिप्त संस्करण

उपरोक्त कोड के साथ एक समस्या यह है कि यह थोड़ा बोझिल है। इस वजह से, आप एक संक्षिप्त संस्करण देखने की अधिक संभावना रखते हैं जो लगभग वही काम करता है:

class MyClass
  def my_method1
    @my_method1 ||= some_long_calculation
  end

  def my_method2
    @my_method2 ||= begin
      # begin-end ब्लॉक आपको आसानी से
      # यहां कई लाइनों कोड का उपयोग करने देता है।
    end
  end
end

ये दोनों Ruby के a ||= b ऑपरेटर का उपयोग करते हैं, जो a || (a = b) के लिए शॉर्टहैंड है, जो स्वयं कमोबेश इसके लिए शॉर्टहैंड है:

# आप वास्तविक जीवन में इस तरह return का उपयोग नहीं करेंगे।
# मैं सिर्फ शुरुआती लोगों को यह विचार व्यक्त करने के लिए इसका उपयोग कर रहा हूँ
# कि कंडीशनल का मूल्यांकन जो भी `a` में समाप्त होता है उस पर होता है।
if a
  return a
else
  a = b
  return a
end

बग्स का एक स्रोत

यदि आप बहुत ध्यान दे रहे हैं तो आपने देखा होगा कि संक्षिप्त संस्करण मेमो वेरिएबल के "ट्रुथीनेस" का मूल्यांकन करते हैं बजाय इसके अस्तित्व की जांच करने के। यह संक्षिप्त संस्करण की प्रमुख सीमाओं में से एक का स्रोत है: यह nil या false को कभी मेमोइज़ नहीं करता।

ऐसे बहुत सारे उपयोग के मामले हैं जहां यह महत्वपूर्ण नहीं है। लेकिन यह उन कष्टप्रद तथ्यों में से एक है जिसे आपको हमेशा अपने दिमाग के पीछे रखना होगा जब भी आप मेमोइज़ कर रहे हों।

आर्गुमेंट्स वाले मेथड्स को मेमोइज़ करना

अब तक हमने केवल सिंगल वैल्यूज़ को मेमोइज़ करने का काम किया है। लेकिन कई फंक्शन्स हर समय एक ही परिणाम नहीं लौटाते। आइए तकनीकी इंटरव्यू के एक पुराने पसंदीदा पर नज़र डालते हैं: फाइबोनैचि अनुक्रम।

आप Ruby में फाइबोनैचि अनुक्रम को पुनरावर्ती रूप से इस तरह कैलकुलेट कर सकते हैं:

class Fibonacci
  def self.calculate(n)
    return n if n == 0 || n == 1
    calculate(n - 1) + calculate(n - 2)
  end
end

Fibonacci.calculate(10) # => 55

इस कार्यान्वयन के साथ समस्या यह है कि यह अकुशल है। इसे साबित करने के लिए, आइए n के मान को देखने के लिए एक print स्टेटमेंट जोड़ें।

class Fibonacci
  def self.calculate(n)
    print "#{ n } "
    return n if n == 0 || n == 1
    calculate(n - 1) + calculate(n - 2)
  end
end

Fibonacci.calculate(4)
# आउटपुट: 4 3 2 1 0 1 2 1 0

जैसा कि आप देख सकते हैं, calculate को n के समान मानों के साथ बार-बार कॉल किया जा रहा है। वास्तव में calculate के कॉल्स की संख्या n के साथ एक्सपोनेंशियली बढ़ने वाली है।

इसका एक तरीका calculate के परिणामों को मेमोइज़ करना है। ऐसा करना हमारे द्वारा कवर किए गए अन्य मेमोइज़ेशन उदाहरणों से बहुत अलग नहीं है।

class Fibonacci
  def self.calculate(n)
    @calculate ||= {}
    @calculate[n] ||= begin
      print "#{ n } "
      if n == 0 || n == 1
        n
      else
        calculate(n - 1) + calculate(n - 2)
      end
    end
  end
end

Fibonacci.calculate(4)
# आउटपुट: 4 3 2 1 0

अब जब हमने calculate को मेमोइज़ कर लिया है, तो कॉल्स की संख्या अब n के साथ एक्सपोनेंशियली नहीं बढ़ती।

Fibonacci.calculate(20)
# आउटपुट: 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

अमान्यता

मेमोइज़ेशन कैशिंग की तरह है, सिवाय इसके कि मेमोइज़्ड परिणाम स्वचालित रूप से समाप्त नहीं होते हैं, और एक बार सेट होने के बाद उन्हें साफ़ करने का आमतौर पर कोई आसान तरीका नहीं होता।

फाइबोनैचि अनुक्रम जनरेटर जैसे उपयोग-मामलों के लिए यह शायद ही मायने रखता है। Fibonacci.calculate(10) हमेशा वही परिणाम लौटाएगा। लेकिन अन्य उपयोग के मामलों में यह मायने रखता है।

उदाहरण के लिए, आप ऐसा कोड देख सकते हैं:

# सबसे अच्छा विचार नहीं
class User
  def full_name
    @full_name ||= [first_name, last_name].join(" ")
  end
end

व्यक्तिगत रूप से, मैं यहां मेमोइज़ेशन का उपयोग नहीं करूंगा क्योंकि यदि पहला या अंतिम नाम बदलता है, तो पूरा नाम अपडेट नहीं हो सकता है।

एक जगह जहां आप थोड़ा अधिक लापरवाह हो सकते हैं वह है Rails कंट्रोलर्स के अंदर। ऐसा कोड देखना बहुत आम है:

class ApplicationController
  def current_user
    @current_user ||= User.find(...)
  end
end

यह ठीक है, क्योंकि कंट्रोलर इंस्टेंस प्रत्येक वेब रिक्वेस्ट के बाद नष्ट हो जाता है। किसी सामान्य रिक्वेस्ट के दौरान वर्तमान में लॉग-इन यूजर के बदलने की संभावना नहीं है।

एक्शनकेबल जैसे स्ट्रीमिंग कनेक्शन के साथ काम करते समय आपको अधिक सावधान रहने की आवश्यकता हो सकती है। मुझे नहीं पता। मैंने कभी इसका उपयोग नहीं किया।

अति-उपयोग

अंत में मुझे लगता है कि मुझे यह बताना चाहिए कि किसी भी चीज़ की तरह, मेमोइज़ेशन को बहुत दूर तक ले जाना संभव है। यह एक तकनीक है जिसे वास्तव में केवल महंगे ऑपरेशन्स पर लागू किया जाना चाहिए जो मेमो वेरिएबल के जीवनकाल के दौरान कभी नहीं बदलेंगे।

  1. Ruby on Rails के लिए पर्यावरण चर में महारत हासिल करें: एक पूर्ण गाइड Ruby on Rails के लिए पर्यावरण चर में महारत हासिल करें: एक पूर्ण गाइड

    यदि आप विकास और प्रोडक्शन में वेब ऐप्स को प्रभावी ढंग से प्रबंधित करना चाहते हैं, तो आपको पर्यावरण चर को समझना होगा। यह हमेशा ऐसा नहीं था। कुछ साल पहले, शायद ही कोई अपने Rails ऐप्स को पर्यावरण चर के साथ कॉन्फ़िगर कर रहा था। लेकिन फिर Heroku हुआ। Heroku ने डेवलपर्स को 12-फैक्टर ऐप दृष्टिकोण से परिचित

  1. रूबी में इनपुट और आउटपुट (IO) में महारत हासिल करें: एक व्यापक गाइड रूबी में इनपुट और आउटपुट (IO) में महारत हासिल करें: एक व्यापक गाइड

    I/O का अर्थ है इनपुट/आउटपुट। इनपुट से हमारा तात्पर्य उस सभी डेटा और जानकारी से है जो किसी चीज़ में आती है (कंप्यूटर, रूबी मेथड, आपका दिमाग)। इनपुट के उदाहरण: कीबोर्ड पर आपके द्वारा दबाई गई कीज़ माउस क्लिक आपके द्वारा पढ़ी गई किताबें आउटपुट से हमारा तात्पर्य उस हर चीज़ से है जो इनपुट के परिणामस्वरू

  1. Mac सुरक्षा: अपने Mac को सुरक्षित रखने के लिए एक व्यापक गाइड Mac सुरक्षा: अपने Mac को सुरक्षित रखने के लिए एक व्यापक गाइड

    क्या Mac को एंटीवायरस की आवश्यकता है? दशकों से Macs का असाधारण सुरक्षा रिकॉर्ड रहा है, मुख्य रूप से दो कारणों से। एक यह है कि Macs मजबूत सुरक्षात्मक सुविधाओं और बहुत कम शोषक भेद्यताओं के साथ बनाए गए हैं। दूसरा यह है कि दुनिया का अधिकांश हिस्सा PC का मालिक है, इसलिए साइबर अपराधियों ने अपने प्रयासों क