क्या एसिंक्स्ट वेट कीवर्ड एक कंटिन्यू लैम्बडा के बराबर है?


81

क्या कोई कृपया पुष्टि करने के लिए पर्याप्त हो सकता है कि क्या मैंने Async प्रतीक्षा कीवर्ड को सही ढंग से समझा है? (CTP के संस्करण 3 का उपयोग करते हुए)

इस प्रकार अब तक मैंने काम किया है कि एक विधि कॉल करने से पहले प्रतीक्षा कीवर्ड सम्मिलित करना 2 चीजें अनिवार्य रूप से करता है, ए। यह एक तत्काल रिटर्न बनाता है और बी। यह एक "निरंतरता" बनाता है जिसे एस्किंक विधि के आह्वान के पूरा होने पर आमंत्रित किया जाता है। किसी भी मामले में निरंतरता विधि के लिए कोड ब्लॉक का शेष है।

इसलिए जो मैं सोच रहा हूं कि क्या ये दो बिट्स कोड तकनीकी रूप से समतुल्य हैं, और यदि ऐसा है, तो क्या इसका मूल रूप से यह अर्थ है कि प्रतीक्षा कीवर्ड एक कंटिन्यू लैम्ब्डा बनाने के समान है (यानी: मूल रूप से एक के लिए एक कंपाइलर शॉर्टकट)? यदि नहीं, तो अंतर क्या हैं?

bool Success =
    await new POP3Connector(
        "mail.server.com", txtUsername.Text, txtPassword.Text).Connect();
// At this point the method will return and following code will
// only be invoked when the operation is complete(?)
MessageBox.Show(Success ? "Logged In" : "Wrong password");

बनाम

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text ).Connect())
.ContinueWith((success) =>
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password"));

जवाबों:


83

सामान्य विचार सही है - शेष विधि को निरंतरता में बनाया गया है।

"फास्ट पथ" ब्लॉग पोस्ट कैसे का विवरण दिया गया async/ awaitसंकलक परिवर्तन काम करता है।

अंतर, मेरे सिर के ऊपर से:

awaitकीवर्ड भी एक "शेड्यूलिंग संदर्भ" की अवधारणा का उपयोग करता है। शेड्यूलिंग संदर्भ SynchronizationContext.Currentयदि मौजूद है, तो वापस गिर रहा है TaskScheduler.Current। निरंतरता को शेड्यूलिंग संदर्भ पर चलाया जाता है। तो एक करीब सन्निकटन पारित करने के लिए किया जाएगा TaskScheduler.FromCurrentSynchronizationContextमें ContinueWith, पर वापस गिरने TaskScheduler.Currentयदि आवश्यक हो तो।

वास्तविक async/ awaitकार्यान्वयन पैटर्न मिलान पर आधारित है; यह "प्रतीक्षा योग्य" पैटर्न का उपयोग करता है जो कार्यों के अलावा अन्य चीजों की प्रतीक्षा करने की अनुमति देता है। कुछ उदाहरण WinRT अतुल्यकालिक API हैं, कुछ विशेष विधियाँ जैसे कि Yield, Rx वेधशालाएँ, और विशेष सॉकेट वेइटेबल्स जो GC को कठोर रूप में नहीं मारते हैं । कार्य शक्तिशाली हैं, लेकिन वे केवल प्रतीक्षारत नहीं हैं।

एक और मामूली नाइटपिक अंतर मन में आता है: अगर प्रतीक्षा पहले से ही पूरी हो गई है, तो asyncविधि वास्तव में उस बिंदु पर वापस नहीं आती है; यह समकालिक रूप से जारी है। तो यह एक तरह से गुजरने जैसा है TaskContinuationOptions.ExecuteSynchronously, लेकिन स्टैक-संबंधित समस्याओं के बिना।


2
बहुत अच्छी तरह से कहा - मैं जॉन के पदों को टालने की कोशिश करता हूं क्योंकि वे एसओ पर जवाब देने के लिए मेरे पास जितना समय होगा, उससे कहीं अधिक व्यापक हैं, लेकिन स्टीफन बिल्कुल सही हैं। WRT क्या awaitable (और विशेष रूप से GetAwaiter) है, अपने पद # 3 बहुत उपयोगी IMHO :) है msmvps.com/blogs/jon_skeet/archive/2011/05/13/...
जेम्स मैनिंग

4
यहां पर स्टीफन का स्थान है। सरल उदाहरणों के लिए यह सोचना आसान है कि एसिंक्स / वेट सिर्फ कंटिन्यू के लिए एक शॉर्टकट है - हालांकि, मैं इसके बारे में उल्टा सोचना पसंद करता हूं। Async / wait वास्तव में आपके लिए ContinueWith का उपयोग करने के लिए उपयोग की जाने वाली एक अधिक शक्तिशाली अभिव्यक्ति है। मुद्दा यह है कि ContinueWith (...) लैम्ब्डा का उपयोग करता है, और निष्पादन को जारी रखने के लिए स्थानांतरित करने की अनुमति देता है, लेकिन अन्य नियंत्रण प्रवाह अवधारणाएं जैसे कि लूप्स बहुत असंभव हैं यदि आपको कंटिन्यूविथ (..) से पहले लूप बॉडी का आधा भाग डालना है। ।) और दूसरे आधे के बाद। आप मैन्युअल निरंतरता के साथ अंत करते हैं।
थियो यंग

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

2
Async / प्रतीक्षा का अंतिम भाग यह उल्लेखनीय है कि यह एक "उच्च स्तर की अवधारणा" है जबकि ContinueWith (...) अधिक मैनुअल है और स्पष्ट रूप से इसमें लैम्ब्डा, डेलिगेट क्रिएशंस आदि हैं। उच्च स्तर की अवधारणाओं के साथ अनुकूलन के लिए अधिक अवसर हैं - इसलिए उदाहरण के लिए, एकाधिक एक ही विधि में वास्तव में एक ही लैम्ब्डा क्लोजर "शेयर" का इंतजार कर रहा है (यह एक सिंगल लैम्ब्डा के ओवरहेड की तरह है), जबकि कंटीन्यूथ (...) हर बार ओवरहेड हो जाता है, क्योंकि आप स्पष्ट रूप से लैम्बडा लिखते हैं, इसलिए संकलक आपको वह देता है।
थियो यंग

1
@MobyDisk: स्पष्ट करने के लिए, awaitअभी भी SynchronizationContext.Currentहमेशा की तरह कब्जा कर लेता है। लेकिन ASP.NET Core पर SynchronizationContext.Currentहै null
स्टीफन क्लीयर

8

यह "अनिवार्य रूप से" है, लेकिन उत्पन्न कोड कड़ाई से अधिक है। उत्पन्न कोड पर बहुत अधिक विवरण के लिए, मैं अत्यधिक जॉन स्कीट की एडुआसिंक श्रृंखला की सिफारिश करूंगा:

http://codeblog.jonskeet.uk/category/eduasync/

विशेष रूप से, # 7 पोस्ट हो जाता है कि क्या उत्पन्न होता है (CTP 2 के रूप में) और क्यों, तो शायद इस समय जो आप देख रहे हैं उसके लिए एक महान फिट:

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/

संपादित करें: मुझे लगता है कि आप प्रश्न से क्या देख रहे हैं, इसकी तुलना में अधिक विवरण होने की संभावना है, लेकिन अगर आप सोच रहे हैं कि जब आप विधि में एकाधिक प्रतीक्षा कर रहे हैं तो क्या चीजें दिखती हैं, तो यह पद # 9 में शामिल है :)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generated-code-for-multiple-awaits/

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