रोसेलिन में एसिंक्स स्टेट मशीन क्लासेस (और स्ट्रक्चर्स नहीं) क्यों हैं?


86

आइए इस बहुत ही सरल एस्कॉन विधि पर विचार करें:

static async Task myMethodAsync() 
{
    await Task.Delay(500);
}

जब मैं इसे VS2013 (पूर्व रोसलिन कंपाइलर) के साथ संकलित करता हूं तो उत्पन्न स्थिति-मशीन एक संरचना है।

private struct <myMethodAsync>d__0 : IAsyncStateMachine
{  
    ...
    void IAsyncStateMachine.MoveNext()
    {
        ...
    }
}

जब मैं इसे VS2015 (रोसलिन) के साथ संकलित करता हूं तो उत्पन्न कोड यह है:

private sealed class <myMethodAsync>d__1 : IAsyncStateMachine
{
    ...
    void IAsyncStateMachine.MoveNext()
    {
        ...
    }
}

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

क्या किसी को पता है कि रोजलिन में इसे फिर से क्यों बदला गया? (मुझे इससे संबंधित कोई समस्या नहीं है, मुझे पता है कि यह परिवर्तन पारदर्शी है और किसी भी कोड के व्यवहार को नहीं बदलता है, मैं सिर्फ उत्सुक हूं)

संपादित करें:

@Damien_The_Unbeliever (और स्रोत कोड :)) से जवाब imho सब कुछ बताते हैं। रोसलिन का वर्णित व्यवहार केवल डिबग बिल्ड के लिए लागू होता है (और टिप्पणी में उल्लिखित CLR सीमा के कारण इसकी आवश्यकता है)। रिलीज में यह एक संरचना भी उत्पन्न करता है (उस के सभी लाभों के साथ ..)। तो यह एडिट एंड कंटेंट और उत्पादन में बेहतर प्रदर्शन दोनों का समर्थन करने के लिए एक बहुत ही चतुर समाधान प्रतीत होता है। दिलचस्प सामान, भाग लेने वाले सभी लोगों के लिए धन्यवाद!


2
मुझे संदेह है कि उन्होंने तय किया कि जटिलता (फिर से परिवर्तनशील संरचनाएं) इसके लायक नहीं थीं। asyncविधियों में लगभग हमेशा एक वास्तविक एसिंक्रोनस बिंदु होता है - जो awaitकि पैदावार को नियंत्रित करता है, जिसके लिए संरचना को वैसे भी बॉक्स करना होगा। मेरा मानना ​​है कि संरचनाएं केवल उन यादों के दबावों को दूर करेंगी asyncजो तुल्यकालिक रूप से चलने के लिए हुई थीं।
स्टीफन क्लीयर

जवाबों:


112

मेरे पास इसका कोई पूर्वज्ञान नहीं था, लेकिन चूंकि रोजलिन इन दिनों खुला-स्रोत है, इसलिए हम एक स्पष्टीकरण के लिए कोड के माध्यम से शिकार पर जा सकते हैं।

और यहाँ, AsyncRewriter की लाइन 60 पर , हम पाते हैं:

// The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class.
var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct;

इसलिए, structएस का उपयोग करने के लिए कुछ अपील करते हुए , संपादन औरasync तरीकों के भीतर काम करना जारी रखने की बड़ी जीत जाहिर तौर पर बेहतर विकल्प के रूप में चुनी गई थी।


18
बहुत अच्छी पकड़! और इसी के आधार पर यहाँ मैंने भी खोज की है: यह केवल तब होता है जब आप इसे डीबग में बनाते हैं (समझ में आता है, कि जब आप EnC करते हैं ..), लेकिन रिलीज़ में वे एक संरचना बनाते हैं (जाहिर है कि EnableEditAndContinue उस में झूठी है ..) ।)। Btw। मैंने कोड देखने की भी कोशिश की, लेकिन यह नहीं मिला। बहुत धन्यवाद!
ग्रैगैकलापोस

3

इस तरह से कुछ के लिए एक निश्चित जवाब देना मुश्किल है (जब तक कि कंपाइलर टीम का कोई व्यक्ति :) में नहीं है), लेकिन कुछ बिंदु हैं जिन पर आप विचार कर सकते हैं:

प्रदर्शन "स्ट्रक्चर्स" बोनस हमेशा एक ट्रेडऑफ़ होता है। मूल रूप से, आपको निम्नलिखित मिलते हैं:

  • मूल्य शब्दार्थ
  • संभव स्टैक (शायद रजिस्टर भी?) आवंटन
  • परोक्ष से परहेज

प्रतीक्षित मामले में इसका क्या मतलब है? खैर, वास्तव में ... कुछ भी नहीं। केवल एक बहुत ही कम समय अवधि है जिसके दौरान राज्य मशीन स्टैक पर है - याद रखें, awaitप्रभावी रूप से एक करता है return, इसलिए विधि स्टैक मर जाती है; राज्य मशीन को कहीं संरक्षित किया जाना चाहिए, और यह कि "कहीं" निश्चित रूप से ढेर पर है। ढेर जीवनकाल अतुल्यकालिक कोड अच्छी तरह से फिट नहीं है :)

इसके अलावा, राज्य मशीन संरचनाओं को परिभाषित करने के लिए कुछ अच्छे दिशानिर्देशों का उल्लंघन करती है:

  • structs अधिकतम 16-बाइट्स पर होना चाहिए - राज्य मशीन में दो पॉइंटर्स होते हैं, जो अपने आप 16-बाइट की सीमा को 64-बिट पर बड़े करीने से भर देते हैं। इसके अलावा, वहाँ राज्य ही है, इसलिए यह "सीमा" पर चला जाता है। यह एक बड़ी बात नहीं है , क्योंकि यह काफी संभावना है कि यह केवल संदर्भ द्वारा पारित किया गया है, लेकिन ध्यान दें कि यह संरचना के लिए उपयोग के मामले में बिल्कुल फिट नहीं है - एक संरचना जो मूल रूप से एक संदर्भ प्रकार है।
  • structs अपरिवर्तनीय होना चाहिए - ठीक है, यह शायद एक टिप्पणी की ज्यादा जरूरत नहीं है। यह एक राज्य मशीन है । फिर से, यह एक बड़ी बात नहीं है, क्योंकि संरचना ऑटो-जनरेट कोड और निजी है, लेकिन ...
  • structs को तार्किक रूप से एकल मान का प्रतिनिधित्व करना चाहिए। निश्चित रूप से यहाँ मामला नहीं है, लेकिन यह पहले से ही एक उत्परिवर्ती राज्य होने से पहले से ही इस प्रकार का है।
  • यह अक्सर बॉक्सिंग नहीं किया जाना चाहिए - यहाँ एक समस्या नहीं है, क्योंकि हम हर जगह जेनरिक का उपयोग कर रहे हैं । राज्य अंततः ढेर पर कहीं है, लेकिन कम से कम यह बॉक्सिंग (स्वचालित रूप से) नहीं किया जा रहा है। फिर, तथ्य यह है कि यह केवल आंतरिक रूप से उपयोग किया जाता है यह बहुत अधिक शून्य बनाता है।

और हां, यह सब एक ऐसे मामले में है जहां कोई बंद नहीं है। जब आपके पास स्थानीय (या फ़ील्ड्स) होते हैं जो awaitएस को पार करते हैं , तो राज्य को और फुलाया जाता है, एक संरचना का उपयोग करने की उपयोगिता को सीमित करता है।

यह सब देखते हुए, वर्ग दृष्टिकोण निश्चित रूप से क्लीनर है, और मैं structइसके बजाय किसी भी ध्यान देने योग्य प्रदर्शन वृद्धि की अपेक्षा नहीं करूंगा । शामिल वस्तुओं की सभी समान जीवन है, इसलिए स्मृति के प्रदर्शन में सुधार करने के लिए एक ही रास्ता बनाने के लिए किया जाएगा सभी उनमें से structजो सामान्य स्थिति में असंभव है, ज़ाहिर है - (उदाहरण के लिए, कुछ बफर में स्टोर) रों। और ज्यादातर मामले जहां आप awaitपहली जगह में उपयोग करेंगे (यानी, कुछ अतुल्यकालिक I / O काम) में पहले से ही अन्य वर्ग शामिल हैं - उदाहरण के लिए, डेटा बफ़र्स, स्ट्रिंग्स ... यह बल्कि संभावना नहीं awaitहै कि आप कुछ ऐसा करेंगे जो 42बिना किसी काम किए ही वापस आ जाए ढेर आवंटन।

अंत में, मैं केवल वही स्थान कहूँगा जहाँ आप वास्तव में वास्तविक प्रदर्शन अंतर देखेंगे, बेंचमार्क होंगे। और बेंचमार्क के लिए अनुकूलन एक मूर्खतापूर्ण विचार है, कम से कम कहने के लिए ...


आपको हमेशा कंपाइलर टीम के सदस्य की आवश्यकता नहीं होती है जब आप स्रोत को पढ़ने और पढ़ने जा सकते हैं, और उन्होंने एक उपयोगी टिप्पणी छोड़ दी है :-)
Damien_The_Unbeliever

3
@Damien_The_Unbeliever हाँ, यह निश्चित रूप से एक शानदार खोज थी, मैंने पहले ही आपके उत्तर को
गलत कर

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