इन दिनों #freeze
. देखना बहुत आम है रूबी कोड में उपयोग किया जाता है। लेकिन अक्सर यह पूरी तरह से स्पष्ट नहीं होता है कि फ्रीज का उपयोग क्यों किया जा रहा है। इस पोस्ट में हम सबसे सामान्य कारणों को देखेंगे जो एक डेवलपर चर को फ्रीज कर सकता है। प्रत्येक कारण को स्पष्ट करने के लिए, मैंने रेल कोडबेस और अन्य लोकप्रिय ओपन-सोर्स प्रोजेक्ट्स से उदाहरण कोड लिया है।
अपरिवर्तनीय स्थिरांक बनाना
रूबी में, स्थिरांक परिवर्तनशील होते हैं। यह थोड़ा भ्रमित करने वाला है, लेकिन कोड को समझना काफी आसान है। यहाँ, मैंने एक स्ट्रिंग स्थिरांक बनाया है और उसमें एक और स्ट्रिंग जोड़ रहा हूँ।
MY_CONSTANT = "foo"
MY_CONSTANT << "bar"
puts MY_CONSTANT.inspect # => "foobar"
#freeze का उपयोग करके, मैं एक स्थिरांक बनाने में सक्षम हूँ जो वास्तव में स्थिर है। इस बार, जब मैं स्ट्रिंग को संशोधित करने का प्रयास करता हूं, तो मुझे एक रनटाइम त्रुटि मिलती है।
MY_CONSTANT = "foo".freeze
MY_CONSTANT << "bar" # => RuntimeError: can't modify frozen string
एक्शनडिस्पैच कोडबेस में इसका वास्तविक दुनिया का उदाहरण यहां दिया गया है। रेल संवेदनशील डेटा को "[FILTERED]" टेक्स्ट से बदलकर लॉग में छिपा देता है। यह पाठ एक स्थिर स्थिरांक में संगृहीत है।
module ActionDispatch
module Http
class ParameterFilter
FILTERED = '[FILTERED]'.freeze
...
ऑब्जेक्ट आवंटन कम करना
अपने रूबी ऐप को गति देने के लिए आप जो सबसे अच्छी चीजें कर सकते हैं, उनमें से एक है बनाई गई वस्तुओं की संख्या को कम करना। ऑब्जेक्ट आवंटन का एक कष्टप्रद स्रोत स्ट्रिंग अक्षर से आता है जो अधिकांश ऐप्स में छिड़का जाता है।
हर बार जब आप लॉग ("फोबार") जैसी विधि कॉल करते हैं, तो आप एक नया स्ट्रिंग ऑब्जेक्ट बनाते हैं। यदि आपका कोड प्रति सेकंड हजारों बार इस तरह की विधि को कॉल करता है, तो इसका मतलब है कि आप प्रति सेकंड हजारों तार बना रहे हैं (और कचरा इकट्ठा कर रहे हैं)। यह बहुत अधिक है!
सौभाग्य से, रूबी हमें एक रास्ता देती है। यदि हम स्ट्रिंग अक्षर को फ्रीज करते हैं, तो रूबी दुभाषिया केवल एक स्ट्रिंग ऑब्जेक्ट बनाएगा और भविष्य में उपयोग के लिए इसे कैश करेगा। मैंने जमे हुए बनाम गैर-जमे हुए स्ट्रिंग तर्कों के प्रदर्शन को दिखाते हुए एक त्वरित बेंचमार्क एक साथ रखा है। यह लगभग 50% प्रदर्शन वृद्धि दर्शाता है।
require 'benchmark/ips'
def noop(arg)
end
Benchmark.ips do |x|
x.report("normal") { noop("foo") }
x.report("frozen") { noop("foo".freeze) }
end
# Results with 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
यदि आप रेल राउटर को देखते हैं तो आप इसे क्रिया में देख सकते हैं। चूंकि प्रत्येक वेब पेज अनुरोध के लिए राउटर का उपयोग किया जाता है, इसलिए इसे तेज़ होना चाहिए। इसका मतलब है कि बहुत सारे जमे हुए स्ट्रिंग अक्षर।
# excerpted from 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
रूबी में बिल्ट-इन ऑप्टिमाइज़ेशन>=2.2
रूबी 2.2 और बाद के संस्करण (एमआरआई) स्वचालित रूप से स्ट्रिंग अक्षर को फ्रीज कर देंगे जो हैश कुंजी के रूप में उपयोग किए जाते हैं।
user = {"name" => "george"}
# In Ruby >= 2.2
user["name"]
# ...is equivalent to this, in Ruby <= 2.1
user["name".freeze]
और Matz के अनुसार, रूबी 3 में सभी स्ट्रिंग अक्षर स्वचालित रूप से जमे हुए होंगे।
लिंक:DevelopersMeeting20150820जापान - रूबी 3.0 में स्ट्रिंग अक्षर डिफ़ॉल्ट रूप से जमे हुए (अपरिवर्तनीय) हैं https://t.co/4XcelftmSa
- युकिहिरो मात्सुमोतो (@yukihiro_matz) अगस्त 20, 2015
वैल्यू ऑब्जेक्ट और फंक्शनल प्रोग्रामिंग
जबकि रूबी एक कार्यात्मक प्रोग्रामिंग भाषा नहीं है, कई रूबीवादियों ने एक कार्यात्मक शैली में काम करने के मूल्य को देखना शुरू कर दिया है। इस शैली के मुख्य सिद्धांतों में से एक यह है कि आपको साइड इफेक्ट से बचना चाहिए। प्रारंभ होने के बाद वस्तुओं को कभी नहीं बदलना चाहिए।
कंस्ट्रक्टर के अंदर फ्रीज विधि को कॉल करके, यह गारंटी देना संभव है कि कोई वस्तु कभी नहीं बदलेगी। अनजाने में हुए किसी भी दुष्प्रभाव के परिणामस्वरूप एक अपवाद उठाया जाएगा।
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