2013-06-22 7 views
10

मैं http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx?cs-save-lang=1&cs-lang=csharp पर एसिंक्रोनस फ़ंक्शन कॉल के बारे में पढ़ रहा था।एक सिंक्रोनस कॉल से async w/await अलग कैसे है?

Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); 

// You can do work here that doesn't rely on the string from GetStringAsync. 
DoIndependentWork(); 

string urlContents = await getStringTask; 

लेकिन तब वे समझाने कि वहाँ का मतलब समय में किया जाना कोई काम नहीं है, तो आप बस इसे इस तरह कर सकते हैं:

पहला उदाहरण में, वे इस है, जो मैं मिलता है:

string urlContents = await client.GetStringAsync(); 

मैं क्या समझ से, await कीवर्ड समारोह रिटर्न जब तक कोड प्रवाह निलंबित कर देगा। तो यह कैसे अलग है:

string urlContents = client.GetString(); 

?

+0

यह मुख्य निष्पादन संदर्भ/धागा को अवरुद्ध नहीं करता है, इसलिए उदा। UI को जमे हुए नहीं किया जाएगा (यूआई का उपयोग करने वाले एप्लिकेशन में)। –

+0

लेकिन यह मुख्य रूप से इसलिए है क्योंकि विधि स्वयं ही 'async' है, है ना? इसका मतलब यह नहीं होगा कि जब तक यह सामानों में व्यस्त हो, तब तक कॉलिंग थ्रेड जारी रह सकता है? – Rijk

+0

नहीं, async की आवश्यकता है ताकि यह प्रतीक्षा कर सके। सभी जादू प्रतीक्षा कॉल पर खुश हैं। – ghord

उत्तर

8

कॉलिंग await client.GetStringAsync() कॉलिंग विधि पर निष्पादन उत्पन्न करता है, जिसका अर्थ है कि यह निष्पादन को समाप्त करने के तरीके की प्रतीक्षा नहीं करेगा, और इस प्रकार थ्रेड को अवरुद्ध नहीं करेगा। एक बार जब यह पृष्ठभूमि में निष्पादित हो जाता है, तो यह तरीका तब से जारी रहेगा जहां से यह बंद हो गया था।

यदि आप केवल client.GetString() पर कॉल करते हैं, तो थ्रेड का निष्पादन तब तक जारी नहीं रहेगा जब तक कि इस विधि को निष्पादित नहीं किया जाता है, जो थ्रेड को अवरुद्ध कर देगा और यूआई को उत्तरदायी बनने का कारण बन सकता है।

उदाहरण:

public void MainFunc() 
{ 
    InnerFunc(); 
    Console.WriteLine("InnerFunc finished"); 
} 

public void InnerFunc() 
{ 
    // This causes InnerFunc to return execution to MainFunc, 
    // which will display "InnerFunc finished" immediately. 
    string urlContents = await client.GetStringAsync(); 

    // Do stuff with urlContents 
} 

public void InnerFunc() 
{ 
    // "InnerFunc finished" will only be displayed when InnerFunc returns, 
    // which may take a while since GetString is a costly call. 
    string urlContents = client.GetString(); 

    // Do stuff with urlContents 
} 
+2

मुझे अंततः यह मिला जब मैंने पढ़ा "सिंक्रोनस और असिंक्रोनस व्यवहार के बीच का अंतर है, एक सिंक्रोनस विधि तब लौटाती है जब उसका काम पूरा हो जाता है, लेकिन एक एसिंक विधि _ कार्य का निलंबित होने पर कार्य मान को वापस कर देता है।"। इसलिए एसिंक्रोनस फ़ंक्शन अभी भी सिंक्रोनस फ़ंक्शंस की तरह व्यवहार करेगा, * जब तक वे 'प्रतीक्षा' कथन जारी नहीं करेंगे, जो कॉलर पर नियंत्रण वापस कर देगा। – Rijk

+1

@Rijk: एक एसिंक्रोनस फ़ंक्शन को 'async' पहचानकर्ता के साथ चिह्नित नहीं किया जाता है - और जरूरी नहीं कि' प्रतीक्षा करें 'जारी करें। 'कार्य' या 'कार्य ' को वापस करने वाला एक सामान्य फ़ंक्शन एसिंक्रोनस फ़ंक्शन के रूप में माना जा सकता है और आप उस पर 'प्रतीक्षा कर सकते हैं'। – YK1

8

मैं क्या समझ से, इंतजार कीवर्ड कोड प्रवाह को निलंबित कर देगा फ़ंक्शन तक

ठीक है, हाँ और नहीं।

  • हां, क्योंकि कोड प्रवाह एक अर्थ में बंद हो जाता है।
  • नहीं, क्योंकि इस कोड प्रवाह को निष्पादित करने वाला धागा अवरुद्ध नहीं होता है। (सिंक्रोनस कॉल client.GetString() धागे को अवरुद्ध करेगा)।

वास्तव में, यह इसकी कॉलिंग विधि पर वापस आ जाएगा। यह समझने के लिए कि इसका क्या मतलब है इसकी कॉलिंग विधि पर लौटने से, आप एक और सी # कंपाइलर जादू - yield return कथन के बारे में पढ़ सकते हैं। जहां yield return बयान के बाद कोड केवल निष्पादित करेंगे के बाद MoveNext() प्रगणक पर कहा जाता है -

yield return साथ

इटरेटर ब्लॉक एक राज्य मशीन में विधि टूट जाएगा। (this और this देखें)।

अब, async/await तंत्र इसी तरह की राज्य मशीन पर भी आधारित है (हालांकि, यह yield return राज्य मशीन से कहीं अधिक जटिल है)।

मामलों को आसान बनाने के लिए, की सुविधा देता है एक सरल async विधि पर विचार:

public async Task MyMethodAsync() 
{ 
    // code block 1 - code before await 

    // await stateement 
    var r = await SomeAwaitableMethodAsync(); 

    // code block 2 - code after await 
} 
  • आप async पहचानकर्ता के साथ एक विधि निशान जब आप एक राज्य मशीन में विधि को तोड़ने के लिए संकलक बता और है कि आप करने जा रहे हैं इस विधि के अंदर await
  • मान लें कि कोड Thread1 पर थ्रेड पर चल रहा है और आपका कोड इस MyMethodAsync() पर कॉल करता है। फिर code block 1 एक ही थ्रेड पर सिंक्रनाइज़ रूप से चलेंगे।
  • SomeAwaitableMethodAsync() को सिंक्रनाइज़ भी कहा जाएगा - लेकिन मान लें कि विधि एक नया एसिंक्रोनस ऑपरेशन शुरू करती है और Task देता है।
  • यह तब होता है जब await तस्वीर में आता है। यह कोड कॉल को अपने कॉलर पर वापस कर देगा और थ्रेड Thread1 कॉलर्स कोड चलाने के लिए स्वतंत्र है। कॉलिंग विधि में क्या होता है इस पर निर्भर करता है कि कॉलिंग विधि await एस MyMethodAsync() पर है या कुछ और करता है - लेकिन महत्वपूर्ण बात Thread1 अवरुद्ध नहीं है।
  • अब प्रतीक्षा का जादू बाकी है - जब SomeAwaitableMethodAsync() द्वारा लौटाया गया कार्य अंततः पूरा हो जाता है, तो code block 2अनुसूचित चलाने के लिए है।
  • async/await कार्य समांतर पुस्तकालय पर बनाया गया है - इसलिए, टीपीएल पर शेड्यूलिंग किया गया है।
  • अब यह बात यह है कि यह code block 2 उसी धागे Thread1 पर निर्धारित नहीं किया जा सकता है जब तक कि यह थ्रेड एफ़िनिटी (जैसे WPF/WinForms UI थ्रेड) के साथ सक्रिय SynchronizationContext सक्रिय न हो। awaitSynchronizationContext जागरूक है, इसलिए, code block 2SynchronizationContext, यदि कोई हो, तो MyMethodAsync() पर कॉल किया गया था। यदि कोई सक्रिय SynchronizationContext नहीं था, तो सभी संभावनाओं के साथ, code block 2 कुछ अलग थ्रेड पर चलाएगा।

अन्त में, मैं कहना है कि चूंकि async/await संकलक द्वारा बनाई गई राज्य मशीन, yield return की तरह पर आधारित है, यह कमियों के कुछ शेयरों - उदाहरण के लिए, आप नहीं await एक finally अंदर ब्लॉक कर सकते हैं।

मुझे आशा है कि यह आपके संदेहों को साफ़ करेगा।

+0

विस्तृत उत्तर के लिए धन्यवाद! – Rijk

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