नया टुपल टाइप .Net 4.0 में रेफरेंस टाइप (क्लास) क्यों है और वैल्यू टाइप (स्ट्रक्चर) नहीं है


89

किसी को जवाब पता है और / या इस बारे में एक राय है?

चूंकि टुपल्स सामान्य रूप से बहुत बड़े नहीं होंगे, इसलिए मुझे लगता है कि इसके लिए कक्षाओं की तुलना में स्ट्रक्चर्स का उपयोग करना अधिक समझ में आएगा। आपने क्या कहा?


1
2016 के बाद यहाँ ठोकर खाने वाले किसी भी व्यक्ति के लिए। c # 7 और नए में, टुपल लिटरल टाइप परिवार के हैं ValueTuple<...>C # tuple प्रकार
तामीर दानीली

जवाबों:


94

Microsoft ने सरलता के हितों में सभी प्रकार के संदर्भ प्रकार बनाए।

मुझे व्यक्तिगत रूप से लगता है कि यह एक गलती थी। 4 से अधिक फ़ील्ड वाले ट्यूपल्स बहुत ही असामान्य हैं और उन्हें किसी भी प्रकार के अधिक वैकल्पिक विकल्प के साथ प्रतिस्थापित किया जाना चाहिए (जैसे एफ # में एक रिकॉर्ड प्रकार) इसलिए केवल छोटे ट्यूपल्स व्यावहारिक रुचि के हैं। मेरे स्वयं के बेंचमार्क ने दिखाया कि 512 बाइट्स तक अनबॉक्स किए गए ट्यूपल्स अभी भी बॉक्सिंग ट्यूपल्स की तुलना में तेज हो सकते हैं।

यद्यपि स्मृति दक्षता एक चिंता का विषय है, मेरा मानना ​​है कि प्रमुख मुद्दा .NET गारबेज कलेक्टर का ओवरहेड है। आवंटन और संग्रह .NET पर बहुत महंगे हैं क्योंकि इसका कचरा कलेक्टर बहुत भारी रूप से अनुकूलित नहीं किया गया है (जैसे कि जेवीएम की तुलना में)। इसके अलावा, डिफ़ॉल्ट .NET GC (वर्कस्टेशन) को अभी तक समानांतर नहीं किया गया है। नतीजतन, समानांतर कार्यक्रम जो ट्यूपल्स पीस का उपयोग करते हैं, वे सभी कचरा साझा कलेक्टर के लिए प्रतिस्पर्धा करते हैं, जिससे स्केलेबिलिटी को नष्ट किया जाता है। यह न केवल प्रमुख चिंता का विषय है, बल्कि, AFAIK, Microsoft द्वारा पूरी तरह से उपेक्षित था जब उन्होंने इस समस्या की जांच की।

एक और चिंता आभासी प्रेषण है। संदर्भ प्रकार उप-प्रकारों का समर्थन करते हैं और इसलिए, उनके सदस्यों को आमतौर पर आभासी प्रेषण के माध्यम से आमंत्रित किया जाता है। इसके विपरीत, मूल्य प्रकार उप-प्रकारों का समर्थन नहीं कर सकते हैं, इसलिए सदस्य आह्वान पूरी तरह से अस्पष्ट है और हमेशा एक प्रत्यक्ष फ़ंक्शन कॉल के रूप में किया जा सकता है। वर्चुअल डिस्पैच आधुनिक हार्डवेयर पर बहुत महंगा है क्योंकि सीपीयू यह अनुमान नहीं लगा सकता है कि प्रोग्राम काउंटर कहां समाप्त होगा। वर्चुअल डिस्पैच को ऑप्टिमाइज़ करने के लिए JVM बड़ी लंबाई में जाता है लेकिन .NET ऐसा नहीं करता है। हालाँकि, .NET मान प्रकार के रूप में वर्चुअल प्रेषण से बच प्रदान करता है। इसलिए मूल्य प्रकार के रूप में ट्यूपल्स का प्रतिनिधित्व करना, फिर से, नाटकीय रूप से यहां प्रदर्शन में सुधार कर सकता है। उदाहरण के लिए, कॉलिंगGetHashCode 2-ट्यूपल पर एक लाख बार 0.17 का समय लगता है, लेकिन इसे एक समतुल्य संरचना पर कॉल करने में केवल 0.008s लगते हैं, अर्थात संदर्भ प्रकार की तुलना में मान 20 × तेज होता है।

एक वास्तविक स्थिति जहां ट्यूपल्स के साथ ये प्रदर्शन समस्याएं आमतौर पर उत्पन्न होती हैं, शब्दकोशों में कुंजियों के रूप में ट्यूपल्स के उपयोग में होती हैं। मैं वास्तव में ढेर अतिप्रवाह सवाल एफ से एक लिंक का पालन करके इस धागे पर ठोकर खाई है # पायथन की तुलना में मेरे एल्गोरिथ्म धीमी गति से चलता है! जहां लेखक का F # प्रोग्राम ठीक उसके पायथन की तुलना में धीमा निकला क्योंकि वह बॉक्सिंग ट्यूपल्स का उपयोग कर रहा था। हाथ से लिखे हुए structप्रकार का उपयोग करके मैन्युअल रूप से अनबॉक्सिंग करने से उसका एफ # प्रोग्राम कई बार तेज, और पायथन की तुलना में तेज हो जाता है। ये मुद्दे कभी नहीं उठते यदि ट्यूपल्स को मूल्य प्रकारों से दर्शाया जाता और न कि संदर्भ प्रकारों के साथ शुरू करने के लिए ...


2
@ बेंट: हां, यह ठीक है कि जब मैं एफ # में एक गर्म रास्ते पर ट्यूपल्स पर आता हूं। अच्छा होगा अगर वे .NET फ्रेमवर्क में बॉक्सिंग और अनबॉक्ड टुपल्स दोनों प्रदान किए थे, हालांकि ...
JD

18
आभासी प्रेषण के बारे में, मुझे लगता है कि आपका दोष गलत है: Tuple<_,...,_>प्रकारों को सील किया जा सकता था, जिस स्थिति में संदर्भ प्रकार होने के बावजूद किसी भी आभासी प्रेषण की आवश्यकता नहीं होगी। मैं इस बारे में अधिक उत्सुक हूं कि वे संदर्भ प्रकारों की तुलना में क्यों सील नहीं हैं।
केवीबी

2
मेरे परीक्षण से, उस परिदृश्‍य के लिए, जिसमें एक फ़ंक्शन में एक टुपल जेनरेट किया जाएगा और दूसरे फ़ंक्शन पर वापस लौटा जाएगा, और फिर कभी उपयोग नहीं किया जाएगा, उजागर-क्षेत्र संरचनाएं किसी भी आकार के डेटा आइटम के लिए बेहतर प्रदर्शन की पेशकश करती प्रतीत होती हैं जो उड़ाने के लिए इतनी बड़ी नहीं है। ढेर। अपरिवर्तनीय वर्ग केवल तभी बेहतर होते हैं जब उनके निर्माण लागत (डेटा आइटम को बड़ा करने के लिए संदर्भों को पर्याप्त रूप से पारित किया जाएगा, कम से कम उन्हें उनके पक्ष में व्यापार करने के लिए गोल किया जाना चाहिए)। चूंकि एक टपल को केवल एक साथ अटके हुए चरों के एक समूह का प्रतिनिधित्व करना है, एक संरचना आदर्श प्रतीत होगी।
सुपरकैट

2
"512 बाइट्स तक अनबॉक्स किए गए ट्यूपल्स अभी भी बॉक्सिंग से तेज हो सकते हैं" - वह कौन सा परिदृश्य है? आप 512B डेटा रखने वाले वर्ग उदाहरण की तुलना में 512B संरचना को तेज़ी से आवंटित करने में सक्षम हो सकते हैं, लेकिन इसे पास करना 100 गुना से अधिक धीमा होगा (अनुमान x86)। वहाँ कुछ है जो मैं देख रहा हूँ?
ग्रू


45

कारण सबसे अधिक संभावना है क्योंकि केवल छोटे ट्यूपल्स मूल्य प्रकार के रूप में समझ में आएंगे क्योंकि उनके पास एक छोटा मेमोरी फुटप्रिंट होगा। बड़े ट्यूपल्स (यानी अधिक गुणों वाले) वास्तव में प्रदर्शन में पीड़ित होंगे क्योंकि वे 16 बाइट्स से बड़े होंगे।

इसके बजाय कुछ टुपल्स मान प्रकार के होते हैं और अन्य संदर्भ प्रकार होते हैं और डेवलपर्स को यह जानने के लिए मजबूर करते हैं कि कौन से लोग हैं जो माइक्रोसॉफ्ट पर लोगों की कल्पना करेंगे कि उन्हें सभी संदर्भ प्रकार सरल बनाने थे।

आह, संदेह की पुष्टि! कृपया बिल्डिंग टपल देखें :

पहला बड़ा निर्णय यह था कि क्या एक संदर्भ या मूल्य प्रकार के रूप में टुपल्स का इलाज किया जाए। चूँकि वे किसी भी समय अपरिवर्तनीय हैं, आप एक टुपल के मूल्यों को बदलना चाहते हैं, आपको एक नया बनाना होगा। यदि वे संदर्भ प्रकार हैं, तो इसका मतलब है कि यदि आप एक तंग लूप में एक नलिका में तत्वों को बदल रहे हैं तो बहुत अधिक कचरा उत्पन्न हो सकता है। एफ # टुपल्स संदर्भ प्रकार थे, लेकिन टीम से एक भावना थी कि वे एक प्रदर्शन में सुधार का एहसास कर सकते हैं यदि दो, और शायद तीन, तत्व ट्यूपल्स इसके बजाय मूल्य प्रकार थे। आंतरिक ट्यूपल्स बनाने वाली कुछ टीमों ने संदर्भ प्रकारों के बजाय मूल्य का उपयोग किया था, क्योंकि उनके परिदृश्य बहुत सारे प्रबंधित ऑब्जेक्ट बनाने के लिए बहुत संवेदनशील थे। उन्होंने पाया कि मूल्य प्रकार का उपयोग करने से उन्हें बेहतर प्रदर्शन मिला। टपल विनिर्देश के हमारे पहले मसौदे में, हमने शेष प्रकारों के साथ दो-, तीन- और चार-तत्व वाले ट्यूल को मूल्य प्रकार के रूप में रखा। हालांकि, एक डिज़ाइन मीटिंग के दौरान जिसमें अन्य भाषाओं के प्रतिनिधि शामिल थे, यह निर्णय लिया गया था कि यह "स्प्लिट" डिज़ाइन दोनों प्रकारों के बीच थोड़ा अलग शब्दार्थ होने के कारण भ्रमित होगा। संभावित प्रदर्शन बढ़ने की तुलना में व्यवहार और डिजाइन में स्थिरता उच्च प्राथमिकता के लिए निर्धारित की गई थी। इस इनपुट के आधार पर, हमने डिज़ाइन को बदल दिया ताकि सभी ट्यूपल्स संदर्भ प्रकार हों, हालांकि हमने एफ # टीम से यह देखने के लिए कुछ प्रदर्शन जांच करने के लिए कहा कि क्या यह ट्यूपल्स के कुछ आकारों के लिए मूल्य प्रकार का उपयोग करते समय स्पीडअप का अनुभव करता है। इसका परीक्षण करने का यह एक अच्छा तरीका था, क्योंकि इसके संकलक ने F # में लिखा था, एक बड़े कार्यक्रम का एक अच्छा उदाहरण था, जो विभिन्न प्रकार के परिदृश्यों में ट्यूपल्स का उपयोग करता था। अंत में, एफ # टीम ने पाया कि जब कुछ टुपल्स संदर्भ प्रकारों के बजाय मूल्य प्रकार थे, तो इसे प्रदर्शन में सुधार नहीं मिला। इसने हमें ट्यूपल के लिए संदर्भ प्रकारों का उपयोग करने के हमारे निर्णय के बारे में बेहतर महसूस कराया।


3
यहाँ महान चर्चा: blogs.msdn.com/bclteam/archive/2009/07/07/…
कीथ एडलर

हाँ! मैंने देखा। मैं अभी भी थोड़ा उलझन में हूं कि मूल्य प्रकार का यहां अभ्यास में कोई मतलब नहीं है: पी
बेंट रासमुसेन

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

7
आपकी "16 बाइट" की सीमा फर्जी है। जब मैंने .NET 4 पर इसका परीक्षण किया तो मैंने पाया कि जीसी इतनी धीमी है कि 512 बाइट तक अनबॉक्स किए गए ट्यूपल्स अभी भी तेज हो सकते हैं। मैं Microsoft के बेंचमार्क परिणामों पर भी सवाल उठाऊंगा। मुझे यकीन है कि उन्होंने समानतावाद (एफ # संकलक समानांतर नहीं है) को नजरअंदाज कर दिया है और जहां जीसी से बचना वास्तव में बंद है क्योंकि .NET का कार्य केंद्र GC भी समानांतर नहीं है।
जदयू

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

7

यदि .NET System.Tuple <...> प्रकारों को संरचना के रूप में परिभाषित किया गया था, तो वे स्केलेबल नहीं होंगे। उदाहरण के लिए, इस समय के रूप में लंबे समय के पूर्णांक का एक गुच्छेदार तराजू:

type Tuple3 = System.Tuple<int64, int64, int64>
type Tuple33 = System.Tuple<Tuple3, Tuple3, Tuple3>
sizeof<Tuple3> // Gets 4
sizeof<Tuple33> // Gets 4

यदि टर्नरी ट्यूपल को एक संरचना के रूप में परिभाषित किया गया था, तो परिणाम निम्नानुसार होगा (एक परीक्षण उदाहरण के आधार पर जो मैंने लागू किया):

sizeof<Tuple3> // Would get 32
sizeof<Tuple33> // Would get 104

जैसा कि ट्यूपल्स में F # में अंतर्निहित सिंटैक्स समर्थन है, और वे इस भाषा में बहुत बार उपयोग किए जाते हैं, "संरचना" ट्यूपल्स एफ प्रोग्रामर्स को अक्षम प्रोग्राम लिखने के जोखिम पर बताएंगे, यहां तक ​​कि इसके बारे में पता किए बिना। यह इतनी आसानी से होगा:

let t3 = 1L, 2L, 3L
let t33 = t3, t3, t3

मेरी राय में, "संरचना" ट्यूपल्स रोज़मर्रा की प्रोग्रामिंग में महत्वपूर्ण अक्षमता पैदा करने की एक उच्च संभावना का कारण होगा। दूसरी ओर, वर्तमान में "क्लास" ट्यूपल भी कुछ अक्षमताओं का कारण बनते हैं, जैसा कि @Jon द्वारा उल्लेख किया गया है। हालांकि, मुझे लगता है कि "होने की संभावना" समय "संभावित क्षति" का उत्पाद वर्तमान में कक्षाओं के साथ तुलना में बहुत अधिक होगा। इसलिए, वर्तमान कार्यान्वयन कम बुराई है।

आदर्श रूप से, F # में दोनों सिंटैक्टिक सपोर्ट के साथ "क्लास" टुपल्स और "स्ट्रक्चर" टुपल्स दोनों होंगे!

संपादित करें (2017-10-07)

संरचना टुपल्स अब पूरी तरह से इस प्रकार समर्थित हैं:

  • Mscorlib (.NET> = 4.7) में निर्मित। System.ValueTuple
  • NuGet के रूप में उपलब्ध हैअन्य संस्करणों के लिए के
  • C #> = 7 में सिंथेटिक समर्थन
  • एफ #> = 4.1 में सिंथेटिक समर्थन

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

2
यह हो सकता है कि F # पासिंग स्ट्रक्चर्स के विचार के साथ अच्छी तरह से नहीं खेलता है ref, या इस तथ्य को पसंद नहीं कर सकता है कि तथाकथित "अपरिवर्तनीय स्ट्रक्चर्स" नहीं हैं, खासकर जब बॉक्सिंग। यह बहुत बुरा है। किसी भी लागू करने वाले मापदंडों की अवधारणा को कभी भी लागू नहीं किया जाता है const ref, क्योंकि कई मामलों में ऐसे शब्दार्थ हैं जो वास्तव में आवश्यक हैं।
सुपरकैट

1
संयोग से, मैं वस्तुओं को आवंटित करने की लागत का हिस्सा होने के नाते जीसी की परिशोधित लागत का संबंध रखता हूं; यदि आवंटन के प्रत्येक मेगाबाइट के बाद एक L0 GC आवश्यक होगा, तो 64 बाइट्स आवंटित करने की लागत L0 GC की लागत का लगभग 1 / 16,000 है, साथ ही किसी भी L1 या L2 GC की लागत का एक अंश जो कि आवश्यक हो जाता है इसका परिणाम है।
सुपरकैट

4
"मुझे लगता है कि घटना की संभावना समय के संभावित नुकसान की तुलना में यह वर्तमान में कक्षाओं के साथ तुलना में बहुत अधिक होगा।" एफडब्ल्यूआईडब्लू, मैंने बहुत मुश्किल से टुपल्स को जंगली में देखा है और उन्हें एक डिजाइन दोष माना जाता है, लेकिन मैं बहुत बार लोगों को भयानक प्रदर्शन के साथ संघर्ष करते हुए देखता हूं जब (रेफरी) ट्यूल को कुंजी के रूप में उपयोग करते हैं Dictionary, जैसे कि यहां: stackoverflow.com/estestions/5850243 /…
JD

3
@Jon यह दो साल है क्योंकि मैंने यह जवाब लिखा है, और मैं अब आपके साथ सहमत हूं कि अगर यह कम से कम 2- और 3-ट्यूपल्स संरचित था तो यह बेहतर होगा। इस संबंध में एक एफ # भाषा उपयोगकर्ता की आवाज का सुझाव दिया गया है। इस मुद्दे में कुछ तात्कालिकता है, क्योंकि हाल के वर्षों में बड़े डेटा, मात्रात्मक वित्त और गेमिंग में अनुप्रयोगों का बड़े पैमाने पर विकास हुआ है।
मार्क सिग्रिस्ट 10

4

2-ट्यूपल के लिए, आप अभी भी कॉमन टाइप सिस्टम के पुराने संस्करणों से हमेशा KeyValuePair <TKey, TValue> का उपयोग कर सकते हैं। यह एक मूल्य प्रकार है।

मैट एलिस लेख के लिए एक मामूली स्पष्टीकरण यह होगा कि संदर्भ और मूल्य प्रकारों के बीच शब्दार्थ का उपयोग करने में अंतर केवल "मामूली" होता है जब अपरिवर्तनीयता प्रभाव में होती है (जो निश्चित रूप से, यहां मामला होगा)। फिर भी, मुझे लगता है कि बीसीएल डिजाइन में यह सबसे अच्छा रहा होगा कि कुछ सीमा पर टुपल क्रॉस को एक संदर्भ प्रकार पर रखने का भ्रम न हो।


यदि एक बार वापस आने के बाद किसी मूल्य का उपयोग किया जाएगा, तो किसी भी आकार की एक उजागर-क्षेत्र संरचना किसी अन्य प्रकार से बेहतर प्रदर्शन करेगी, बशर्ते कि स्टैक को उड़ाने के लिए यह इतनी विशाल रूप से विशाल न हो। यदि किसी संदर्भ को कई बार साझा किया जाता है, तो क्लास ऑब्जेक्ट के निर्माण की लागत को फिर से प्राप्त किया जाएगा। एक बार जब यह एक सामान्य-उद्देश्य के लिए उपयोगी आकार-प्रकार के विषम वर्ग के लिए उपयोगी होता है, लेकिन ऐसे समय होते हैं जब कोई संरचना बेहतर होती है - यहां तक ​​कि "बड़ी" चीजों के लिए भी।
सुपरकैट

इस उपयोगी नियम को जोड़ने के लिए धन्यवाद। मैं हालांकि उम्मीद कर रहा हूं कि आपने मेरी स्थिति को गलत नहीं समझा: मैं एक मूल्य-प्रकार के नशेड़ी हूं। ( stackoverflow.com/a/14277068 को कोई संदेह नहीं छोड़ना चाहिए)।
ग्लेन स्लेडेन

मान प्रकार .net की महान विशेषताओं में से एक है, लेकिन दुर्भाग्य से एमएसडीएन डॉक्स को लिखने वाले व्यक्ति यह पहचानने में विफल रहे कि उनके लिए कई अलग-अलग उपयोग के मामले हैं, और यह कि अलग-अलग उपयोग के मामलों में अलग-अलग दिशानिर्देश हैं। Msdn की सिफारिश की गई शैली का उपयोग केवल उन संरचनाओं के साथ किया जाना चाहिए जो एक समरूप मूल्य का प्रतिनिधित्व करती हैं, लेकिन अगर किसी को डक्ट टेप के साथ मिलकर बनाए गए कुछ स्वतंत्र मूल्यों का प्रतिनिधित्व करने की आवश्यकता है, तो किसी को उस शैली की संरचना का उपयोग नहीं करना चाहिए - एक के साथ एक संरचना का उपयोग करना चाहिए सार्वजनिक क्षेत्रों को उजागर किया।
सुपरकैट

0

मुझे नहीं पता लेकिन अगर आपने कभी F # Tuples का इस्तेमाल किया है तो वह भाषा का हिस्सा है। अगर मैंने एक .dll बनाया और एक प्रकार का टुल्ल्स लौटाया, तो उस प्रकार का टाइप करना अच्छा होगा, मुझे अब संदेह है कि F # भाषा का हिस्सा है (.Net 4) कुछ सामान्य संरचनाओं को समायोजित करने के लिए CLR में कुछ संशोधन किए गए थे। F # में

से http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records

let scalarMultiply (s : float) (a, b, c) = (a * s, b * s, c * s);;

val scalarMultiply : float -> float * float * float -> float * float * float

scalarMultiply 5.0 (6.0, 10.0, 20.0);;
val it : float * float * float = (30.0, 50.0, 100.0)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.