मुझे संरचना बनाम OpenStruct का उपयोग कब करना चाहिए?


184

सामान्य तौर पर, एक संरचना की तुलना में OpenStruct का उपयोग करने के फायदे और नुकसान क्या हैं? किस प्रकार के सामान्य उपयोग-मामले इनमें से प्रत्येक में फिट होंगे?


1
मेरी हालिया ब्लॉग टिप्पणी "स्ट्रक्चर्स इनसाइड आउट" में स्ट्रक्चर बनाम ओपनस्ट्रक्चर बनाम हैश के बारे में कुछ टिप्पणी है , बस किसी को दिलचस्पी है।
रॉबर्ट क्लेमे

हैश, संरचना और OpenStruct की गति के बारे में जानकारी पुरानी है। अधिक हाल के बेंचमार्क के लिए stackoverflow.com/a/43987844/128421 देखें ।
द टिन मैन

जवाबों:


172

A के साथ OpenStruct, आप मनमाने ढंग से विशेषताएँ बना सकते हैं। एक Struct, दूसरे हाथ पर, जब आप इसे बनाने के उसके गुण परिभाषित होने चाहिए। एक के ऊपर एक का चुनाव मुख्य रूप से इस बात पर आधारित होना चाहिए कि क्या आपको बाद में विशेषताओं को जोड़ने में सक्षम होना चाहिए।

उनके बारे में सोचने का तरीका एक तरफ हैश के बीच स्पेक्ट्रम का मध्य मैदान है और दूसरी तरफ कक्षाएं। वे डेटा के बीच एक अधिक ठोस संबंध की तुलना में एक करते हैं Hash, लेकिन उनके पास एक वर्ग के रूप में उदाहरण के तरीके नहीं हैं। एक समारोह के लिए विकल्पों का एक गुच्छा, उदाहरण के लिए, हैश में समझदारी; वे केवल शिथिल संबंधित हैं। किसी फ़ंक्शन द्वारा आवश्यक नाम, ईमेल और फ़ोन नंबर को एक साथ Structया में पैक किया जा सकता है OpenStruct। यदि उस नाम, ईमेल और फोन नंबर को "प्रथम अंतिम" और "अंतिम, पहला" दोनों स्वरूपों में नाम प्रदान करने के लिए तरीकों की आवश्यकता है, तो आपको इसे संभालने के लिए एक वर्ग बनाना चाहिए।


49
"लेकिन उनके पास कक्षा के रूप में उदाहरण के तरीके नहीं हैं"। ठीक है, "सामान्य वर्ग" के रूप में इसका उपयोग करने के लिए एक बहुत ही सामान्य पैटर्न है:class Point < Struct.new(:x, :y); methods here; end
टोकुलैंड

10
@tokland आज के लिए, विधियों के साथ संरचना को अनुकूलित करने का "पसंदीदा" दृष्टिकोण ब्लॉक टू कंस्ट्रक्टर को पास करना है Point = Struct.new(:x, :y) { methods here }। ( स्रोत ) बेशक, { ... }वहाँ एक मल्टी-लाइन ब्लॉक ( do ... end) के रूप में लिखा जा सकता है और मुझे लगता है, यह पसंदीदा तरीका है।
इवान कोलेमिचेक

1
@ इवानकोल्मेक: कूल, वास्तव में मैं ब्लॉक दृष्टिकोण पसंद करता हूं।
टोक़

@ टॉकलैंड अच्छा है। मैं सिर्फ यह स्पष्ट करना चाहता था कि अब एक अच्छा दृष्टिकोण है, क्योंकि आपकी टिप्पणी को अत्यधिक वोट दिया गया है, इसलिए, माणिक के लिए नए लोग वास्तव में सोच सकते हैं "ठीक है, इसलिए इसे कैसे किया जाना चाहिए, क्योंकि हर कोई इस बात से सहमत है, सही ? " :)
इवान कोलमीक

4
एक प्रश्न: एक बार जब आप अपनी संरचना में तरीकों को जोड़ना चाहते हैं, तो एक कक्षा का उपयोग क्यों करें?
jaydel

82

अन्य बेंचमार्क:

require 'benchmark'
require 'ostruct'

REP = 100000

User = Struct.new(:name, :age)

USER = "User".freeze
AGE = 21
HASH = {:name => USER, :age => AGE}.freeze

Benchmark.bm 20 do |x|
  x.report 'OpenStruct slow' do
    REP.times do |index|
       OpenStruct.new(:name => "User", :age => 21)
    end
  end

  x.report 'OpenStruct fast' do
    REP.times do |index|
       OpenStruct.new(HASH)
    end
  end

  x.report 'Struct slow' do
    REP.times do |index|
       User.new("User", 21)
    end
  end

  x.report 'Struct fast' do
    REP.times do |index|
       User.new(USER, AGE)
    end
  end
end

अधीर के लिए जो बेंचमार्क परिणामों का विचार प्राप्त करना चाहते हैं, उन्हें स्वयं चलाने के बिना, यहां ऊपर दिए गए कोड का आउटपुट है (एक एमबी प्रो 2.4GHz i7 पर)

                          user     system      total        real
OpenStruct slow       4.430000   0.250000   4.680000 (  4.683851)
OpenStruct fast       4.380000   0.270000   4.650000 (  4.649809)
Struct slow           0.090000   0.000000   0.090000 (  0.094136)
Struct fast           0.080000   0.000000   0.080000 (  0.078940)

5
रूबी 2.14 के साथ अंतर 0.94-0.97 ओपनस्ट्रक्ट बनाम 0.02-0.03 के साथ ओस्ट्रेट (एमबी प्रो 2.2Ghz i7) के साथ है
बेसएक्स

1
OpenStruct स्ट्रक्चर का उपयोग करने की गति के बराबर है। Stackoverflow.com/a/43987844/128421 देखें ।
द टिन मैन

57

अपडेट करें:

रूबी के रूप में 2.4.1 OpenStruct और संरचना गति में बहुत करीब हैं। Https://stackoverflow.com/a/43987844/128421 देखें

पहले:

पूर्णता के लिए: संरचना बनाम कक्षा बनाम हैश बनाम ओपनस्ट्रीम

रूबी 1.9.2, (1 के 4 कोर x86_64, 8 जीबी रैम में से 1) पर इसी तरह के कोड को चलाना [स्तंभ संरेखित करने के लिए संपादित तालिका]:

1 Mio संरचनाएं बनाना: 1.43 सेकंड, 219 MB / 90MB (गुण / रेस)
1 Mio क्लास इंस्टेंसेस बनाना: 1.43 सेकंड, 219 MB / 90MB (पुण्य / रेस)
1 Mio हैशिंग बनाना: 4.46 सेकंड, 493 MB / 364MB (पुण्य / रेस)
1 Mio OpenStructs बनाना: 415.13 सेकंड, 2464 MB / 2.3GB (गुण / रेस) # Hashes की तुलना में 100x धीमा
100K OpenStructs बनाना: 10.96 सेकंड, 369 MB / 242MB (गुण / रेस)

OpenStructs हैं sloooooow और स्मृति गहन , और बड़े डेटा सेट के लिए अच्छी तरह से बड़े पैमाने नहीं है

1 Mio OpenStructs बनाना ~ Mio Hashes बनाने की तुलना में ~ 100x धीमा है

start = Time.now

collection = (1..10**6).collect do |i|
  {:name => "User" , :age => 21}
end; 1

stop = Time.now

puts "#{stop - start} seconds elapsed"

खुद की तरह प्रदर्शन नशेड़ी के लिए बहुत उपयोगी जानकारी। धन्यवाद।
बर्नार्डो ओलिवेरा

मैं मैटी के रूबी (एमआरआई) के कार्यान्वयन की बात कर रहा हूं
टिलो

1
हाय @Tilo, क्या आप उपरोक्त परिणाम प्राप्त करने के लिए अपना कोड साझा कर सकते हैं? मैं इसका उपयोग हाशी :: मैश के साथ स्ट्रक्चर और OStruct की तुलना करने के लिए करना चाहता हूं। धन्यवाद।
डॉनी कुर्निया

1
हे @ डॉनी, मैंने अभी-अभी अपवोट देखा और महसूस किया कि यह 2011 में मापा गया था - मुझे रूबी 2.1 के साथ इसे फिर से चलाने की जरूरत है: मुझे यकीन नहीं है कि मेरे पास यह कोड है, लेकिन इसे पुन: पेश करने के लिए सरल होना चाहिए। मैं जल्द ही इसे ठीक करने की कोशिश करूंगा।
तिलो

2
रूबी के रूप में 2.4.1 OpenStruct और संरचना गति में बहुत करीब हैं। देखें stackoverflow.com/a/43987844/128421
टिन मैन

34

दोनों के लिए उपयोग के मामले काफी भिन्न हैं।

आप रूबी 1.9 में संरचना वर्ग को structसी में घोषणा के बराबर मान सकते हैं । रूबी Struct.newमें तर्कों के रूप में फ़ील्ड नामों का एक सेट लेता है और एक नया वर्ग देता है। इसी तरह, सी में, एक structघोषणापत्र खेतों का एक सेट लेता है और प्रोग्रामर को नए जटिल प्रकार का उपयोग करने की अनुमति देता है जैसे वह किसी भी प्रकार का निर्माण करता है।

माणिक:

Newtype = Struct.new(:data1, :data2)
n = Newtype.new

सी:

typedef struct {
  int data1;
  char data2;
} newtype;

newtype n;

OpenStruct वर्ग की तुलना सी में अनाम संरचना घोषणा से की जा सकती है। यह प्रोग्रामर को एक जटिल प्रकार का उदाहरण बनाने की अनुमति देता है ।

माणिक:

o = OpenStruct.new(data1: 0, data2: 0) 
o.data1 = 1
o.data2 = 2

सी:

struct {
  int data1;
  char data2;
} o;

o.data1 = 1;
o.data2 = 2;

यहाँ कुछ सामान्य उपयोग के मामले हैं।

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

h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2

शॉर्टहैंड क्लास परिभाषाओं के लिए संरचनाएं उपयोगी हो सकती हैं।

class MyClass < Struct.new(:a,:b,:c)
end

m = MyClass.new
m.a = 1

3
यह उनके बीच वैचारिक अंतर का एक बड़ा जवाब है। OpenStruct की गुमनामी को इंगित करने के लिए धन्यवाद, मुझे ऐसा लगता है कि यह बहुत अधिक स्पष्ट है।
ब्रायंट

महान व्याख्या!
यूरी घनेश

24

OpenStructs काफी अधिक मेमोरी का उपयोग करते हैं और स्ट्रक्चर बनाम स्लो परफॉर्मर होते हैं।

require 'ostruct' 

collection = (1..100000).collect do |index|
   OpenStruct.new(:name => "User", :age => 21)
end

मेरे सिस्टम पर निम्नलिखित कोड 14 सेकंड में निष्पादित किया गया और 1.5 जीबी मेमोरी का उपभोग किया गया। आपका माइलेज भिन्न हो सकता है:

User = Struct.new(:name, :age)

collection = (1..100000).collect do |index|
   User.new("User",21)
end

यह लगभग तुरंत समाप्त हो गया और 26.6 एमबी मेमोरी का उपभोग किया।


3
लेकिन आप जानते हैं कि OpenStruct परीक्षण बहुत अस्थायी हैश बनाता है। मैं थोड़ा संशोधित बेंचमार्क सुझाता हूं - जो अभी भी आपके फैसले का समर्थन करता है (नीचे देखें)।
रॉबर्ट क्ल्मे

6

Struct:

>> s = Struct.new(:a, :b).new(1, 2)
=> #<struct a=1, b=2>
>> s.a
=> 1
>> s.b
=> 2
>> s.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>

OpenStruct:

>> require 'ostruct'
=> true
>> os = OpenStruct.new(a: 1, b: 2)
=> #<OpenStruct a=1, b=2>
>> os.a
=> 1
>> os.b
=> 2
>> os.c
=> nil

उदाहरण के लिए धन्यवाद। यह अभ्यास में समझने में बहुत मदद करता है।
अहसान

5

नई विधि के संबंध में एपीआई पर एक नजर है। बहुत सारे अंतर वहां पाए जा सकते हैं।

व्यक्तिगत रूप से, मैं काफी OpenStruct पसंद करता हूं, क्योंकि मुझे ऑब्जेक्ट की संरचना को पहले से परिभाषित नहीं करना है, और जैसा मैं चाहता हूं, वैसे ही सामान जोड़ें। मुझे लगता है कि इसका मुख्य (डिस) लाभ होगा?


3

@Robert कोड का उपयोग करके, मैं Hashie :: मैश को बेंचमार्क आइटम में जोड़ता हूं और यह परिणाम मिला है:

                           user     system      total        real
Hashie::Mash slow      3.600000   0.000000   3.600000 (  3.755142)
Hashie::Mash fast      3.000000   0.000000   3.000000 (  3.318067)
OpenStruct slow       11.200000   0.010000  11.210000 ( 12.095004)
OpenStruct fast       10.900000   0.000000  10.900000 ( 12.669553)
Struct slow            0.370000   0.000000   0.370000 (  0.470550)
Struct fast            0.140000   0.000000   0.140000 (  0.145161)

आपका बेंचमार्क वास्तव में अजीब है। मुझे i5 मैक पर रूबी 2.1.1 के साथ निम्नलिखित परिणाम मिला: gist.github.com/nicolas-besnard/…
cappie013

ठीक है, परिणाम उपयोग किए गए रूबी संस्करण और इसे चलाने के लिए उपयोग किए जाने वाले हार्डवेयर के बीच भिन्न होगा। लेकिन पैटर्न अभी भी वही है, OpenStruct सबसे धीमा है, संरचना सबसे तेज है। हाशी बीच में पड़ जाती है।
डॉनी कुर्निया

0

वास्तव में सवाल का जवाब नहीं है, लेकिन एक बहुत महत्वपूर्ण विचार है अगर आप प्रदर्शन के बारे में परवाह करते हैं । कृपया ध्यान दें कि हर बार जब आप OpenStructऑपरेशन करते हैं, तो विधि कैश को साफ़ करता है, जिसका अर्थ है कि आपका आवेदन धीमा प्रदर्शन करेगा। धीमेपन या नहीं के OpenStructबारे में सिर्फ यह नहीं है कि यह अपने आप से कैसे काम करता है, बल्कि इसका अर्थ है कि उनका उपयोग पूरे आवेदन को लाता है: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructs

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