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

Ruby में freeze और frozen का उपयोग कब करें: इम्यूटेबिलिटी के लिए सर्वोत्तम प्रथाएं

आजकल Ruby कोड में #freeze का उपयोग देखना बहुत आम है। लेकिन यह अक्सर पूरी तरह से स्पष्ट नहीं होता कि freeze का उपयोग क्यों किया जा रहा है। इस पोस्ट में हम उन सबसे सामान्य कारणों को देखेंगे जिनकी वजह से एक डेवलपर वेरिएबल्स को फ्रीज कर सकता है। प्रत्येक कारण को स्पष्ट करने के लिए, मैंने Rails कोडबेस और अन्य लोकप्रिय ओपन-सोर्स प्रोजेक्ट्स से उदाहरण कोड लिया है।

इम्यूटेबल कॉन्स्टेंट्स बनाना

Ruby में, कॉन्स्टेंट्स म्यूटेबल होते हैं। यह थोड़ा भ्रमित करने वाला है, लेकिन कोड समझना आसान है। यहां, मैंने एक स्ट्रिंग कॉन्स्टेंट बनाई है और उसमें दूसरी स्ट्रिंग जोड़ रहा हूँ।

MY_CONSTANT = "foo"
MY_CONSTANT << "bar"
puts MY_CONSTANT.inspect # => "foobar"

#freeze का उपयोग करके, मैं एक कॉन्स्टेंट बना सकता हूँ जो वास्तव में कॉन्स्टेंट है। इस बार, जब मैं स्ट्रिंग को संशोधित करने का प्रयास करता हूँ, तो मुझे एक RuntimeError मिलता है।

MY_CONSTANT = "foo".freeze
MY_CONSTANT << "bar" # => RuntimeError: can't modify frozen string

ActionDispatch कोडबेस में इसका एक वास्तविक-विश्व उदाहरण है। Rails लॉग्स में संवेदनशील डेटा को "[FILTERED]" टेक्स्ट से बदलकर छुपाता है। यह टेक्स्ट एक फ्रोज़न कॉन्स्टेंट में स्टोर किया जाता है।

module ActionDispatch
  module Http
    class ParameterFilter
      FILTERED = '[FILTERED]'.freeze
      ...

ऑब्जेक्ट एलोकेशन घटाना

अपने Ruby ऐप को तेज़ करने के लिए आप जो सबसे अच्छी चीजें कर सकते हैं, उनमें से एक है बनने वाले ऑब्जेक्ट्स की संख्या कम करना। अधिकांश ऐप्स में बिखरे स्ट्रिंग लिटरल्स से ऑब्जेक्ट एलोकेशन का एक कष्टप्रद स्रोत आता है।

हर बार जब आप log("foobar") जैसा मेथड कॉल करते हैं, तो आप एक नया String ऑब्जेक्ट बनाते हैं। यदि आपका कोड इस तरह के मेथड को प्रति सेकंड हजारों बार कॉल करता है, तो इसका मतलब है कि आप प्रति सेकंड हजारों स्ट्रिंग्स बना (और गार्बेज-कलेक्ट कर) रहे हैं। यह बहुत अधिक ओवरहेड है!

सौभाग्य से, Ruby हमें एक रास्ता देता है। यदि हम स्ट्रिंग लिटरल्स को फ्रीज करते हैं, तो Ruby इंटरप्रेटर केवल एक String ऑब्जेक्ट बनाएगा और भविष्य के उपयोग के लिए इसे कैश करेगा। मैंने फ्रोज़न बनाम नॉन-फ्रोज़न स्ट्रिंग आर्गुमेंट्स के प्रदर्शन को दिखाने वाला एक त्वरित बेंचमार्क तैयार किया है। यह लगभग 50% प्रदर्शन वृद्धि दिखाता है।

require 'benchmark/ips'
def noop(arg) end
Benchmark.ips do |x|
  x.report("normal") { noop("foo") }
  x.report("frozen") { noop("foo".freeze) }
end
# MRI 2.2.2 के साथ परिणाम:
# Calculating -------------------------------------
# normal 152.123k i/100ms
# frozen 167.474k i/100ms
# -------------------------------------------------
# normal 6.158M (± 3.3%) i/s - 30.881M
# frozen 9.312M (± 3.5%) i/s - 46.558M

आप इसे एक्शन में देख सकते हैं यदि आप Rails राउटर को देखें। चूंकि राउटर का उपयोग हर वेब पेज रिक्वेस्ट के लिए किया जाता है, इसलिए इसे तेज़ होना चाहिए। इसका मतलब है बहुत सारे फ्रोज़न स्ट्रिंग लिटरल्स।

# https://github.com/rails/rails/blob/f91439d848b305a9d8f83c10905e5012180ffa28/actionpack/lib/action_dispatch/journey/router/utils.rb#L15 से अंश
def self.normalize_path(path)
  path = "/#{path}"
  path.squeeze!('/'.freeze)
  path.sub!(%r{/+\Z}, ''.freeze)
  path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
  path = '/' if path == ''.freeze
  path
end

Ruby 2.2+ में बिल्ट-इन ऑप्टिमाइज़ेशन

Ruby 2.2 और बाद के वर्शन (MRI) स्वचालित रूप से उन स्ट्रिंग लिटरल्स को फ्रीज कर देते हैं जिनका उपयोग हैश कीज़ के रूप में किया जाता है।

user = {"name" => "george"}
# Ruby >= 2.2 में
user["name"] # ...यह Ruby <= 2.1 में इसके समतुल्य है
user["name".freeze]

और Matz के अनुसार, Ruby 3 में सभी स्ट्रिंग लिटरल्स डिफ़ॉल्ट रूप से स्वचालित रूप से फ्रीज हो जाएंगे।

वैल्यू ऑब्जेक्ट्स और फंक्शनल प्रोग्रामिंग

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

कंस्ट्रक्टर के अंदर freeze मेथड को कॉल करके, यह गारंटी देना संभव है कि एक ऑब्जेक्ट कभी नहीं बदलेगा। कोई भी अनजाने साइड-इफेक्ट्स एक एक्सेप्शन उठाएंगे।

class Point
  attr_accessor :x, :y
  def initialize(x, y)
    @x = x
    @y = y
    freeze
  end
  def change
    @x = 3
  end
end

point = Point.new(1,2)
point.change # RuntimeError: can't modify frozen Point
  1. रूबी मैट्रिक्स को समझना: परिभाषा, अनुप्रयोग और उन्हें कैसे बनाएं रूबी मैट्रिक्स को समझना: परिभाषा, अनुप्रयोग और उन्हें कैसे बनाएं

    मैट्रिक्स एक 2D (2-डायमेंशनल) ऐरे है जिसका उपयोग स्प्रेडशीट जैसे डेटा को स्टोर और काम करने के लिए किया जा सकता है। इनका उपयोग किया जा सकता है: टेबल गेम में बोर्ड को दर्शाना (शतरंज, चेकर्स, आदि) आंकड़े और डेटा विश्लेषण प्लॉट्स और ग्राफ़ उत्पन्न करना क्योंकि यह एक शक्तिशाली डेटा संरचना है इसलिए इसका

  1. रूबी स्ट्रक्ट्स और OpenStruct में महारत: कुशल वैल्यू ऑब्जेक्ट्स रूबी स्ट्रक्ट्स और OpenStruct में महारत: कुशल वैल्यू ऑब्जेक्ट्स

    रूबी में स्ट्रक्ट क्या है? एक स्ट्रक्ट एक बिल्ट-इन रूबी क्लास है, इसका उपयोग वैल्यू ऑब्जेक्ट्स उत्पन्न करने वाली नई क्लासेस बनाने के लिए किया जाता है। एक वैल्यू ऑब्जेक्ट संबंधित विशेषताओं को एक साथ संग्रहीत करने के लिए उपयोग किया जाता है। यहां एक उदाहरण है: दो निर्देशांकों (x और y) के साथ एक Point।

  1. रूबी स्ट्रिंग फॉर्मेटिंग आसान: लीडिंग जीरोज, कॉलम और printf स्टाइल रूबी स्ट्रिंग फॉर्मेटिंग आसान: लीडिंग जीरोज, कॉलम और printf स्टाइल

    आइए बात करते हैं कि आप रूबी में स्ट्रिंग्स को कैसे फॉर्मेट कर सकते हैं। आप स्ट्रिंग को फॉर्मेट क्यों करना चाहेंगे? खैर, आप ऐसी चीजें करना चाह सकते हैं जैसे नंबर 10 से कम होने पर भी लीडिंग ज़ीरो हो (उदाहरण: 01, 02, 03...), या कुछ कंसोल आउटपुट को कॉलम में अच्छी तरह से फॉर्मेट किया गया हो। अन्य भाषाओं