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

रेल प्रदर्शन:कैशिंग सही विकल्प कब है?

प्रोग्रामिंग शब्दों में, कैशिंग भविष्य में त्वरित पुनर्प्राप्ति के लिए एक मूल्य (या मान) को संग्रहीत करने के लिए संदर्भित करता है। आम तौर पर, आप इसे उन मानों के साथ करेंगे जो किसी कारण से गणना करने में धीमे हैं; उदाहरण के लिए, उन्हें पुनः प्राप्त करने के लिए एक बाहरी एपीआई को हिट करने की आवश्यकता होती है, या उन्हें उत्पन्न करने के लिए बहुत अधिक संख्या-क्रंचिंग शामिल होती है।

कैश्ड मान अक्सर एक अलग सर्वर पर संग्रहीत होते हैं, जैसे मेम्केड या रेडिस। इन्हें डिस्क या रैम में स्टोर किया जा सकता है। कोड में, हम अक्सर महंगे कार्यों को कई बार कॉल करने से बचने के लिए चर के अंदर डेटा 'कैश' करते हैं।

data = some_calculation()
a(data)
b(data)

आपके द्वारा प्राप्त सभी गति के लिए ट्रेड-ऑफ यह है कि आप पुराने डेटा का उपयोग कर रहे हैं। क्या होगा यदि कैश्ड डेटा 'बासी' हो जाता है और अब सटीक नहीं है? आपको कैश को 'अमान्य' करने के लिए साफ़ करना होगा।

कैशिंग के विरुद्ध तर्क

<ब्लॉकक्वॉट>

जैसा कि पुरानी कहावत है, कंप्यूटर विज्ञान में केवल 2 कठिन समस्याएं हैं:1. नामकरण बातें2. कैश अमान्यकरण3. एक-एक करके त्रुटियां

कैश अमान्यकरण इतना कठिन क्यों है? एक कैश्ड मान, अपने स्वभाव से, एक वास्तविक मूल्य को 'छिपाता' है। किसी भी समय 'वास्तविक' मान बदलता है, आपको (हां, आप, प्रोग्रामर) को कैश को 'अमान्य' करना याद रखना होगा ताकि वह अपडेट हो जाए।

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

  1. फ़ाइल लोड करते समय शब्दों की गणना करें।
  2. इस शब्द-गणना को एक चर (या 'इसे कैश करें') में सहेजें।
  3. वेरिएबल की सामग्री को स्क्रीन पर प्रदर्शित करें।

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

अब, जैसे ही कीस्ट्रोक आते हैं, आप शब्दों (यानी, रिक्त स्थान) का पता लगाएंगे और शब्द काउंटर को बढ़ाएंगे। बेशक, जब उपयोगकर्ता शब्दों को हटा रहा है, तो आप इसे घटा भी देंगे। आसान। पूर्ण। अगला टिकट।

...लेकिन रुकिए, क्या आपको याद है कि जब उपयोगकर्ता क्लिपबोर्ड पर टेक्स्ट काटता है, तो क्या आपको शब्द गणना को अपडेट करना याद है? जब वे टेक्स्ट पेस्ट करते हैं तो क्या होता है? क्या होगा जब वर्तनी-परीक्षक एक टाइपो को दो शब्दों में विभाजित करता है?

यहां समस्या मान को अपडेट नहीं कर रही है, जो काफी मामूली है। समस्या यह है कि आपको इसे हर एक जगह . में अपडेट करना याद रखना होगा . इनमें से केवल एक अपडेट के गुम होने से कैशे अमान्य होने की समस्या होती है, जिसका अर्थ है कि आप उपयोगकर्ता को एक पुराना मान प्रदर्शित करेंगे।

इसे ध्यान में रखते हुए, आप देख सकते हैं कि कैशिंग में जोड़ने से तकनीकी जटिलता और बग के संभावित स्रोत सामने आते हैं। बेशक, इन समस्याओं को हल किया जा सकता है, लेकिन समाधान के रूप में कैशिंग पर जाने से पहले इसे ध्यान में रखना चाहिए।

कैशिंग के बिना गति

यदि हम टेबल से कैशिंग को हटा देते हैं, तो हमारे एप्लिकेशन को तेज करना प्रदर्शन बाधाओं को पहचानने और ठीक करने के बारे में है - सिस्टम जो कि वे हो सकते हैं उससे धीमे हैं। हम उन्हें तीन समग्र श्रेणियों में समूहित कर सकते हैं:

  1. डेटाबेस क्वेरीज़ (या तो बहुत अधिक या बहुत धीमी)
  2. रेंडरिंग देखें
  3. एप्लिकेशन कोड (उदा., भारी गणना करना)

प्रदर्शन पर काम करते समय, प्रगति करने के लिए आपको दो तकनीकों के बारे में जानना आवश्यक है:प्रोफाइलिंग और बेंचमार्किंग।

प्रोफाइलिंग

प्रोफाइलिंग से आपको पता चलता है कि कहां समस्याएं आपके ऐप में हैं:क्या यह पृष्ठ धीमा है क्योंकि टेम्पलेट को प्रस्तुत करना धीमा है? या, क्या यह धीमा है क्योंकि यह डेटाबेस को एक लाख बार मार रहा है?

रेल पर रूबी के लिए, मैं रैक-मिनी-प्रोफाइलर की अनुशंसा करता हूं, जो आपके ऐप के किनारे पर एक अच्छा सा विजेट जोड़ता है। यह आपको एक अच्छा अवलोकन देता है कि आप जिस पृष्ठ को देख रहे हैं उसे प्रस्तुत करने में क्या लगा, जैसे कि कितने डेटाबेस प्रश्नों को निकाल दिया गया, उन्हें कितना समय लगा, और कितने भाग प्रस्तुत किए गए।

उत्पादन के लिए (प्रो-टिप:rack-mini-profiler उत्पादन में अच्छा काम करता है; बस सुनिश्चित करें कि यह केवल कुछ उपयोगकर्ताओं के लिए दिखाई देता है, जैसे कि व्यवस्थापक या डेवलपर्स), स्काईलाइट, न्यू रेलिक और स्काउट सहित ऑनलाइन सेवाएं हैं, जो पेज के प्रदर्शन की निगरानी करती हैं।

आमतौर पर उद्धृत लक्ष्य <= 100ms पेज रेंडरिंग के लिए बहुत अच्छा है, क्योंकि इससे कम कुछ भी उपयोगकर्ता के लिए वास्तविक दुनिया के इंटरनेट उपयोग में किसी भी तरह से पता लगाना मुश्किल है। आपका लक्ष्य कई कारकों के आधार पर अलग-अलग होगा। एक बिंदु पर, भयानक प्रदर्शन के साथ एक विरासत आवेदन पर काम करते समय, मैंने <=1 सेकंड का लक्ष्य बनाया, जो कि बहुत अच्छा नहीं है, लेकिन जब मैंने शुरू किया था, तब से बहुत बेहतर है।

बेंचमार्किंग

एक बार जब हमें पता चल जाता है कि कहां समस्या यह है, तो हम बेंचमार्क का उपयोग यह देखने के लिए कर सकते हैं कि हमारे अनुकूलन का प्रदर्शन पर क्या (यदि कोई हो) प्रभाव पड़ा है। निजी तौर पर, मैं इस तरह के काम के लिए बेंचमार्क-आईपीएस रत्न का उपयोग करना पसंद करता हूं, क्योंकि यह आपको अपने कोड द्वारा किए गए अंतरों को देखने के लिए एक आसान मानव-पठनीय तरीका देता है।

एक तुच्छ उदाहरण के रूप में, यहाँ स्ट्रिंग संयोजन बनाम स्ट्रिंग प्रक्षेप की तुलना है:

require 'benchmark/ips'

@a = "abc"
@b = "def"
Benchmark.ips do |x|
  x.report("Concatenation") { @a + @b }
  x.report("Interpolation") { "#{@a}#{@b}" }
  x.compare!
end

और परिणाम:

Warming up --------------------------------------
       Concatenation   316.022k i/100ms
       Interpolation   282.422k i/100ms
Calculating -------------------------------------
       Concatenation     10.353M (± 7.4%) i/s -     51.512M in   5.016567s
       Interpolation      6.615M (± 6.8%) i/s -     33.043M in   5.023636s

Comparison:
       Concatenation: 10112435.3 i/s
       Interpolation:  6721867.3 i/s - 1.50x  slower

यह हमें एक अच्छा मानव-पठनीय परिणाम देता है, और इंटरपोलेशन कॉन्सटेनेशन (कम से कम हमारे छोटे तारों के लिए) से 1.5 गुना धीमा है। इस कारण से, मेरा सुझाव है कि आप जिस पद्धति को सुधारने का प्रयास कर रहे हैं उसे कॉपी करें और इसे एक नया नाम दें। फिर आप यह देखने के लिए त्वरित तुलनाएं चला सकते हैं कि जैसे-जैसे आप आगे बढ़ते हैं, क्या आप इसके प्रदर्शन में सुधार कर रहे हैं।

प्रदर्शन समस्याओं को ठीक करना

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

डेटाबेस प्रदर्शन

डेटाबेस से संबंधित प्रदर्शन समस्याओं के लिए, देखने के लिए कुछ चीजें हैं। सबसे पहले, खतरनाक 'एन+1 प्रश्नों' से बचें। संग्रह को एक दृश्य में प्रस्तुत करने में अक्सर ऐसी स्थितियां उत्पन्न होती हैं। उदाहरण के लिए, आपके पास 10 ब्लॉग पोस्ट वाला उपयोगकर्ता है, और आप उपयोगकर्ता और उसके सभी पोस्ट प्रदर्शित करना चाहते हैं। एक भोली पहली-कटाई कुछ इस तरह हो सकती है:

# Controller
def show
  @user = User.find(params[:id])
end
# View
Name: <%= @user.name %>
Posts:
  <%= @user.posts each do |post| %>
    <div>Title: <%= post.title %></div>
  <% end %>

ऊपर दिखाया गया दृष्टिकोण उपयोगकर्ता (1 क्वेरी) प्राप्त करेगा और फिर प्रत्येक व्यक्तिगत पोस्ट (एन =10 क्वेरी) के लिए एक क्वेरी को बंद कर देगा, जिसके परिणामस्वरूप कुल 11 (या एन + 1) होंगे। सौभाग्य से, रेल .includes(:post) जोड़कर इस समस्या का एक आसान समाधान प्रदान करता है। आपकी ActiveRecord क्वेरी के लिए। तो, उपरोक्त उदाहरण में, हम नियंत्रक कोड को निम्न में बदलते हैं:

def show
  @user = User.includes(:post).find(params[:id])
end

अब, हम उपयोगकर्ता को लाएंगे और उसके सभी या पोस्ट एक डेटाबेस क्वेरी में।

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

total = Model.all.map(&:somefield).sum

यह डेटाबेस से सभी रिकॉर्ड हथिया रहा है, लेकिन मूल्यों का वास्तविक योग रूबी में होता है। हम डेटाबेस को हमारे लिए गणना करने के द्वारा इसे गति दे सकते हैं:

total = Model.sum(:somefield)

शायद आपको कुछ और जटिल चाहिए, जैसे कि दो स्तंभों को गुणा करना:

total = Model.sum('columna * columnb')

सामान्य डेटाबेस इस तरह के बुनियादी अंकगणित का समर्थन करते हैं और योग और औसत जैसे सामान्य एकत्रीकरण का भी समर्थन करते हैं, इसलिए map(...).sum की तलाश में रहें आपके कोडबेस में कॉल करता है।

प्रदर्शन देखें

हालांकि मैं कहूंगा कि टेम्पलेट से संबंधित प्रदर्शन समस्याएं समाधान के रूप में कैशिंग के लिए खुद को अधिक उधार देती हैं, फिर भी कुछ कम लटके हुए फल हैं जिन्हें आप पहले खारिज करना चाहते हैं।

सामान्य पृष्ठ-लोड समय के लिए, आप जांच सकते हैं कि आप किसी भी जावास्क्रिप्ट या सीएसएस पुस्तकालयों (कम से कम उत्पादन सर्वर पर) के लिए छोटे स्रोतों का उपयोग कर रहे हैं।

इसके अलावा, बड़ी संख्या में आंशिक शामिल किए जाने के लिए देखें। यदि आपका _widget.html.erb टेम्प्लेट को संसाधित होने में 1ms लगते हैं, लेकिन आपके पास पृष्ठ पर 100 विजेट हैं, तो वह 100ms पहले ही चला गया है। एक उपाय यह है कि आप अपने UI पर पुनर्विचार करें। स्क्रीन पर एक बार में 100 विजेट्स का होना आम तौर पर एक अच्छा उपयोगकर्ता अनुभव नहीं होता है, और हो सकता है कि आप किसी प्रकार के पेजिनेशन का उपयोग करना चाहें या, शायद, एक और अधिक कठोर UI/UX ओवरहाल।

एप्लिकेशन कोड प्रदर्शन

यदि आपकी प्रदर्शन समस्या दृश्य या डेटाबेस परतों के बजाय एप्लिकेशन कोड में ही है (यानी, डेटा का हेरफेर), तो आपके पास कुछ विकल्प हैं। एक यह देखने के लिए है कि क्या कम से कम कुछ काम डेटाबेस में या तो ऊपर वर्णित प्रश्नों के रूप में, या डेटाबेस दृश्यों के रूप में, शायद, सुंदर मणि की तरह कुछ के रूप में धकेल दिया जा सकता है)।

एक अन्य विकल्प 'भारी भारोत्तोलन' को पृष्ठभूमि की नौकरी में स्थानांतरित करना है, हालांकि इस तथ्य को संभालने के लिए आपके यूआई में बदलाव की आवश्यकता हो सकती है कि मूल्य अब एसिंक्रोनस रूप से गणना की जा रही है।

मुझे अभी भी कैशिंग की आवश्यकता है; अब क्या?

इस सब के माध्यम से इसे बनाने के बाद, शायद आपने तय कर लिया है कि हाँ, कैशिंग वह समाधान है जिसकी आपको आवश्यकता है। तो आपको क्या करना चाहिए? देखते रहें क्योंकि रूबी ऑन रेल्स में उपलब्ध विभिन्न प्रकार के कैशिंग को कवर करने वाले लेखों की श्रृंखला में यह पहला है।


  1. रूबी केस स्टेटमेंट के कई उपयोग

    जब भी आपको कुछ if / elsif . का उपयोग करने की आवश्यकता हो आप इसके बजाय रूबी केस स्टेटमेंट का उपयोग करने पर विचार कर सकते हैं। इस पोस्ट में, आप कुछ अलग उपयोग के मामलों के बारे में जानेंगे और यह सब वास्तव में हुड के तहत कैसे काम करता है। नोट:अन्य प्रोग्रामिंग भाषाओं में इसे स्विच . के रूप में जाना

  1. अपने रेल ऐप्स के प्रदर्शन को समझने का एक नया तरीका

    क्या आपका रेल ऐप धीमा है? जब एक साधारण दृश्य लोड होने में कुछ सेकंड लगते हैं, तो आपको एक समस्या का पता चलता है। आपके पास बहुत अधिक डेटाबेस कॉल या कुछ धीमी विधियाँ हो सकती हैं। या हो सकता है कि यह स्पीडअप लूप है जिसे किसी ने आपके कोड में डाल दिया और भूल गए। आपको यह पता लगाने में मदद करने के लिए ब

  1. एंड्रॉइड को सही तरीके से प्रदर्शन बढ़ाने के लिए ओवरक्लॉक करें

    नए और अपडेटेड एंड्रॉइड स्मार्टफोन लगातार नए अपडेट और फीचर्स के साथ बाजार में आ रहे हैं। नतीजतन, उन्हें समर्थन देने के लिए अधिक गेम और ऐप नियमित रूप से अपडेट किए जा रहे हैं, इसलिए अधिक बिजली की खपत करते हैं और पुराने स्मार्टफोन को धीमा कर देते हैं। जब आप बहुत सारे ऐप खोलते हैं तो हो सकता है कि आपने अ