2017-11-12 20 views
5

मैं async/await के बारे में कुछ और समझने की कोशिश कर रहा हूं और विशेष रूप से कैसे संकलक async विधि और await पर अतिरिक्त थ्रेड के बिना "रोकें" को जानता है।एक सी # कंपाइलर को एसिंक विधि को काटने का तरीका कैसा लगता है?

उदाहरण के लिए, मान लीजिए कि मैं Task एक बार की तरह

DoSomeStuff(); 
await sqlConnection.OpenAsync(); 
DoSomeOtherStuff(); 

मैं जानता हूँ कि await sqlConnection.OpenAsync(); जहाँ मेरे विधि "निलंबित" हो जाता है कि एक async विधि और धागा है कि लागू यह थ्रेड पूल रिटर्न और डालते हैं जो कनेक्शन खोलने को पूरा कर रहा है, तब उपलब्ध थ्रेड DoSomeOtherStuff() चलाने के लिए मिलता है।

| DoSomeStuff() | "start" opening connection | ------------------------------------ | 
| ---------------------------------------------------------- | DoSomeOtherStuff() - | 

यहां मैं उलझन में हूं। मैं OpenAsync (https://referencesource.microsoft.com/#System.Data/System/Data/Common/DBConnection.cs,e9166ee1c5d11996,references) के स्रोत कोड को देखो और

public Task OpenAsync() { 
     return OpenAsync(CancellationToken.None); 
    } 

    public virtual Task OpenAsync(CancellationToken cancellationToken) { 
     TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>(); 

     if (cancellationToken.IsCancellationRequested) { 
      taskCompletionSource.SetCanceled(); 
     } 
     else { 
      try { 
       Open(); 
       taskCompletionSource.SetResult(null); 
      } 
      catch (Exception e) { 
       taskCompletionSource.SetException(e); 
      } 
     } 

     return taskCompletionSource.Task; 
    } 

मैं कुछ जगह है जहाँ संकलक धागा "कट" करने के लिए पता होगा क्योंकि कार्य एक बाहरी संसाधन के साथ संवाद स्थापित शुरू हो गया है को देखने के लिए कल्पना है, लेकिन मुझे वास्तव में यह नहीं दिखाई देता है, और वास्तव में, Open(); का अर्थ यह है कि यह सिंक्रनाइज़ रूप से प्रतीक्षा कर रहा है। क्या कोई समझा सकता है कि यह कैसे थ्रेडलेस "सच्चे एसिंक" कोड बन जाता है?

+3

ठीक है, OpenAsync का ऐसा कार्यान्वयन वास्तव में "सत्य async" कोड नहीं है। – CodeFuller

+0

सी # कंपाइलर आपके कोड को फिर से लिखता है, यह एक छिपे हुए वर्ग के * दो * तरीकों में बदल जाता है। DoSomeOtherStuff() कॉल दूसरी विधि में है। आपके पास हो सकता है कि किसी भी स्थानीय चर और दोनों भागों में उपयोग किया जाता है उस वर्ग के क्षेत्र बन जाते हैं। Ildasm.exe उपयोगिता का उपयोग कर आप कुछ देख सकते हैं। –

+0

@CodeFuller क्या आप मुझे OpenAsync() के "true async" कार्यान्वयन के उदाहरण के लिए इंगित कर सकते हैं? या दिखाएं कि उपरोक्त 'OpenAsync() 'को सच async के रूप में कैसे लिखा जा सकता है? – Questionaire

उत्तर

5

धागा है कि कहा जाता है निम्नलिखित

await sqlConnection.OpenAsync(); 

जारी किया जाएगा और यह थ्रेड पूल के अंतर्गत आता है कि से इनका उपयोग कर के लिए उपलब्ध होगा इस तथ्य से async-का इंतजार परिणाम उपयोग करने का लाभ। अगर हम एएसपी.नेट आवेदन के बारे में बात कर रहे हैं तो धागा मुक्त हो जाएगा और एक अन्य आने वाले HTTP अनुरोध की सेवा के लिए उपलब्ध होगा। इस प्रकार एएसपी.नेट थ्रेड पूल के थ्रेड हमेशा HTTP अनुरोधों के लिए उपलब्ध होंगे और किसी डेटाबेस के लिए कनेक्शन खोलने और कुछ SQL कथन निष्पादित करने जैसे I/O के लिए उदाहरण के लिए अवरुद्ध नहीं होंगे।

अद्यतन

यह है कि अगर काम आप await करने जा रहे हैं पूरा हो चुका है, अपने कोड तुल्यकालिक चल पाएंगे यहाँ कहा जाना चाहिए।

+0

आपका दूसरा पैराग्राफ, _ ओपन() _ के बारे में, भ्रामक है क्योंकि 'ओपन()' को पृष्ठभूमि थ्रेड पर चलाने की आवश्यकता नहीं है। दिखाया गया कार्यान्वयन तुल्यकालिक है और अपने आप पर, संदर्भ बदलता नहीं है। 'ओपनएसिंक 'और' ओपन 'एक ही संदर्भ पर चलते हैं और कॉल से जुड़े एकल थ्रेड को अवरुद्ध करेंगे। – JSteward

+0

@JSteward मुझे यकीन नहीं है कि आपका तर्क सही है। जैसा कि यहां बताया गया है https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/await *** एक प्रतीक्षा अभिव्यक्ति उस थ्रेड को अवरुद्ध नहीं करती है जिस पर यह निष्पादित हो रहा है **। इसके बजाए, यह संकलक को प्रतीक्षा किए गए कार्य पर निरंतरता के रूप में शेष async विधि को साइन अप करने का कारण बनता है। नियंत्रण तब एसिंक विधि के कॉलर पर वापस आ जाता है। जब कार्य पूरा हो जाता है, तो यह इसकी निरंतरता को आमंत्रित करता है, और एसिंक विधि का निष्पादन फिर से शुरू होता है जहां यह छोड़ा जाता है। * कार्यरत पूरे कार्य में एक अलग थ्रेड में चलाया जाएगा। – Christos

+0

यह व्यवहार केवल तब लागू होता है जब 'कार्य/कार्य ' वापसी विधि का कार्यान्वयन कभी भी वास्तविक असीमित विधि उत्पन्न करता है और प्रतिनिधित्व करता है। यदि कार्यान्वयन तुल्यकालिक और अवरुद्ध है; 'प्रतीक्षा' स्वचालित रूप से किसी अन्य संदर्भ में काम नहीं ले जायेगा। एक अवरुद्ध कार्यान्वयन हमेशा एक प्रतीक्षा योग्य वापसी प्रकार के बावजूद ब्लॉक करेगा। – JSteward

6

आपकी विधि को प्रतीक्षा पर "निलंबित" नहीं होना चाहिए। यदि आप जिस काम का इंतजार कर रहे हैं वह पहले ही पूरा हो चुका है (आपके द्वारा प्रदान किए गए कोड में मामला) - विधि हमेशा सामान्य रूप से जारी रहेगी। जिस विधि को आप देख रहे हैं वह वास्तव में SqlConnection द्वारा उपयोग नहीं किया जाता है, क्योंकि DbConnection आधार वर्ग है और विधि OpenAsync वर्चुअल है। SqlConnection इसे ओवरराइड करता है और वास्तविक असीमित कार्यान्वयन प्रदान करता है। हालांकि, सभी प्रदाता ऐसा नहीं करते हैं और जो वास्तव में कार्यान्वयन का उपयोग नहीं करेंगे, आप अपने प्रश्न में दिखाएंगे।

जब इस तरह के कार्यान्वयन का उपयोग किया जाता है - पूरी चीज किसी थ्रेड स्विच के बिना सिंक्रनाइज़ रूप से चलती है। मान लीजिए आप

public async Task Do() { 
    DoSomeStuff(); 
    await sqlConnection.OpenAsync(); 
    DoSomeOtherStuff(); 
} 

है और तुम प्रदाता जो OpenAsync की असली async संस्करण प्रदान नहीं करता है का उपयोग करें। फिर जब कोई await Do() कहता है - कॉलिंग थ्रेड सभी काम करेगा (DoSomeStuff, OpenAsync, DoSomeOtherStuff)। यदि वह यूआई थ्रेड है - इसे पूरे अवधि के लिए अवरुद्ध कर दिया जाएगा (ऐसी स्थिति अक्सर होती है जब लोग यूआई थ्रेड में ऐसे प्रदाताओं के लिए "async" विधियों का उपयोग करते हैं, यह मानते हुए कि यूआई थ्रेड से काम को किसी भी तरह से बंद कर दिया जाएगा, जो नहीं होता है)।

+0

क्या आप मुझे OpenAsync() के "true async" कार्यान्वयन के उदाहरण के लिए इंगित कर सकते हैं? – Questionaire

+0

@Questionaire यहां SqlConnection का स्रोत कोड है: http: //referencesource.microsoft.com/#System.Data/System/Data/SqlClient/SqlConnection.cs – Evk

+0

@Questionaire असली async अधिकतर असीमित आईओ (फ़ाइलें, सॉकेट) है। आपको इसे पढ़ने में रुचि हो सकती है: https://blog.stephencleary.com/2013/11/there-is-no-thread.html – Evk

संबंधित मुद्दे