रूबी में तारों के बजाय प्रतीकों का उपयोग कब करें?


98

यदि मेरी स्क्रिप्ट में एक ही स्ट्रिंग के कम से कम दो उदाहरण हैं, तो क्या मुझे इसके बजाय एक प्रतीक का उपयोग करना चाहिए?

जवाबों:


175

टी एल; डॉ

अंगूठे का एक सरल नियम हर बार आंतरिक पहचानकर्ताओं की आवश्यकता के लिए प्रतीकों का उपयोग करना है। रूबी <2.2 के लिए केवल प्रतीकों का उपयोग करें जब वे मेमोरी लीक से बचने के लिए गतिशील रूप से उत्पन्न नहीं होते हैं।

पूरा जवाब

स्मृति चिन्हों के कारण गतिशील रूप से उत्पन्न पहचानकर्ताओं के लिए इनका उपयोग न करने का एकमात्र कारण है।

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

प्रतीकों और तारों के कार्यान्वयन के बीच कई अंतर हैं। प्रतीकों के बारे में सबसे महत्वपूर्ण बात यह है कि वे अपरिवर्तनीय हैं । इसका मतलब यह है कि उनका मूल्य कभी नहीं बदला जाएगा। इस वजह से, प्रतीकों को स्ट्रिंग्स की तुलना में तेजी से त्वरित किया जाता है और कुछ ऑपरेशन जैसे दो प्रतीकों की तुलना भी तेज होती है।

यह तथ्य कि एक प्रतीक अपरिवर्तनीय है, रूबी को हर बार जब आप प्रतीक का संदर्भ देते हैं, उसी ऑब्जेक्ट का उपयोग करने की अनुमति देता है, जिससे मेमोरी की बचत होती है। इसलिए हर बार जब दुभाषिया :my_keyइसे पढ़ता है तो इसे फिर से इंस्टैंट करने के बजाय मेमोरी से ले सकता है। यह हर बार एक नए तार को शुरू करने से कम खर्चीला है।

आप एक सूची प्राप्त कर सकते हैं सभी प्रतीक जो पहले से ही कमांड के साथ त्वरित हैं Symbol.all_symbols:

symbols_count = Symbol.all_symbols.count # all_symbols is an array with all 
                                         # instantiated symbols. 
a = :one
puts a.object_id
# prints 167778 

a = :two
puts a.object_id
# prints 167858

a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!

puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.

2.2 से पहले के रूबी संस्करणों के लिए, एक बार एक प्रतीक का संकेत दिए जाने के बाद, यह मेमोरी फिर से कभी भी मुक्त नहीं होगी । मेमोरी को फ्री करने का एकमात्र तरीका एप्लिकेशन को पुनरारंभ करना है। इसलिए गलत तरीके से इस्तेमाल किए जाने पर प्रतीक भी मेमोरी लीक का एक प्रमुख कारण है। मेमोरी रिसाव उत्पन्न करने का सबसे सरल तरीका to_symउपयोगकर्ता इनपुट डेटा पर विधि का उपयोग कर रहा है , क्योंकि यह डेटा हमेशा बदल जाएगा, मेमोरी का एक नया भाग हमेशा के लिए सॉफ़्टवेयर इंस्टेंस में उपयोग किया जाएगा। रूबी 2.2 ने प्रतीक कचरा संग्राहक की शुरुआत की , जो गतिशील रूप से उत्पन्न प्रतीकों को मुक्त करता है, इसलिए प्रतीकों को गतिशील रूप से बनाकर मेमोरी लीक उत्पन्न होती है, यह अब चिंता का विषय नहीं है।

आपके प्रश्न का उत्तर देना:

क्या यह सच है कि मुझे एक स्ट्रिंग के बजाय एक प्रतीक का उपयोग करना होगा यदि मेरे आवेदन या स्क्रिप्ट में कम से कम दो समान तार हैं?

यदि आप जो खोज रहे हैं वह आपके कोड में आंतरिक रूप से उपयोग किए जाने वाला एक पहचानकर्ता है, तो आपको प्रतीकों का उपयोग करना चाहिए। यदि आप आउटपुट प्रिंट कर रहे हैं, तो आपको स्ट्रिंग्स के साथ जाना चाहिए, भले ही यह एक से अधिक बार दिखाई दे, यहां तक ​​कि दो अलग-अलग ऑब्जेक्ट्स को मेमोरी में आवंटित करना।

यहाँ तर्क है:

  1. प्रतीकों को छापना मुद्रण तार की तुलना में धीमा होगा क्योंकि वे तार के लिए डाले जाते हैं।
  2. बहुत सारे अलग-अलग प्रतीकों के होने से आपके एप्लिकेशन के समग्र मेमोरी उपयोग में वृद्धि होगी क्योंकि वे कभी भी अस्वीकृत नहीं होते हैं। और आप एक ही समय में अपने कोड से सभी तार का उपयोग नहीं कर रहे हैं।

मामला @AlanDert द्वारा उपयोग करें

@AlanDert: यदि मैं कई बार% इनपुट जैसे कुछ का उपयोग करता हूं {प्रकार:: चेकबॉक्स} को एचएमएल कोड में, मुझे चेकबॉक्स के रूप में क्या उपयोग करना चाहिए?

मेरे हां।

@AlanDert: लेकिन html पृष्ठ पर एक प्रतीक को प्रिंट करने के लिए, इसे स्ट्रिंग में परिवर्तित किया जाना चाहिए, है ना? फिर इसका उपयोग करने की क्या बात है?

एक इनपुट का प्रकार क्या है? इनपुट के प्रकार का एक पहचानकर्ता जिसका आप उपयोग करना चाहते हैं या कुछ ऐसा जो आप उपयोगकर्ता को दिखाना चाहते हैं?

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

उस ने कहा, हम डेटा का मूल्यांकन यह देखने के लिए क्यों नहीं करते कि तार अधिक तेज़ हैं?

यह एक साधारण बेंचमार्क है जिसे मैंने इसके लिए बनाया है:

require 'benchmark'
require 'haml'

str = Benchmark.measure do
  10_000.times do
    Haml::Engine.new('%input{type: "checkbox"}').render
  end
end.total

sym = Benchmark.measure do
  10_000.times do
    Haml::Engine.new('%input{type: :checkbox}').render
  end
end.total

puts "String: " + str.to_s
puts "Symbol: " + sym.to_s

तीन आउटपुट:

# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68

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


@andrewcockerham आपका प्रदान किया गया लिंक काम नहीं कर रहा है (त्रुटि -404)। आपको लिंक से अंतिम /(बाद strings) को निकालना होगा । यहाँ यह है: www.reactive.io/tips/2009/01/11/the-difference-between-ruby- प्रतीकों-और तार
अतुल खंडूरी

14

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


4
+1। प्रतीक और तार पूरी तरह से अलग चीजें हैं। वास्तव में कोई भ्रम नहीं है जिसके लिए किसी को उपयोग करना है, जब तक कि उन्हें बुरी तरह से सिखाया नहीं गया है (यानी "एक प्रतीक सिर्फ एक अपरिवर्तनीय स्ट्रिंग है" गिरावट)।
जोर्ग डब्ल्यू मित्तग

@ JörgWMittag: बिल्कुल सही।
बोरिस स्टिटनिक

5
आपके पास एक बिंदु है, हालांकि उस प्रश्न का उत्तर न दें जो बनाया गया था। ओपी प्रतीकों के साथ भ्रमित कर रहा है, यह पर्याप्त नहीं है यह बताएं कि यह अलग-अलग चीजें हैं - आपको उसे यह समझने में मदद करनी चाहिए कि वे एक जैसे क्या हैं और वे अलग
फॉटेनस

1
@ JörgWMittag जो पूरे वेब पर हो रहा है, जब तक आप प्रलेखन में नहीं देखते हैं या वे भाग्यशाली हैं जो लोगों को खोजने के लिए पर्याप्त हैं जो चीजों को समझाने के लिए परवाह करते हैं क्योंकि वे वास्तव में हैं।
सरगस

5

यहाँ एक अच्छा स्ट्रिंग बनाम प्रतीक बेंचमार्क है जो मुझे कोडेक अकादमी में मिला है:

require 'benchmark'

string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]

string_time = Benchmark.realtime do
  1000_000.times { string_AZ["r"] }
end

symbol_time = Benchmark.realtime do
  1000_000.times { symbol_AZ[:r] }
end

puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."

आउटपुट है:

String time: 0.21983 seconds.
Symbol time: 0.087873 seconds.

2
आइए हम इस तथ्य पर ध्यान न दें कि यह एक सेकंड का दसवां हिस्सा है।
केसी

यह सब सापेक्ष है। कभी-कभी सौवां मामला।
युरी

2
एक लाख पुनरावृत्तियों पर एक सेकंड का सौवां हिस्सा? अगर आपको लगता है कि आपके कार्यक्रम के लिए सबसे अच्छा अनुकूलन उपलब्ध है, तो मैं पहले से ही बहुत अच्छी तरह से अनुकूलित हूं।
केसी

0
  • हैश प्रमुख पहचानकर्ता के रूप में प्रतीकों का उपयोग करें

    {key: "value"}

  • प्रतीकों आपको एक अलग क्रम में विधि को कॉल करने की अनुमति देते हैं

     डिफ राइट (फ़ाइल :, डेटा :, मोड: "एस्की")
          # संक्षिप्तता के लिए हटा दिया गया
     समाप्त
     लिखना (डेटा: 123, फ़ाइल: "test.txt")
  • एक स्ट्रिंग के रूप में रखने और मेमोरी को बचाने के लिए फ्रीज करें

    label = 'My Label'.freeze

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.