असिंक्रोनस प्रोग्रामिंग कोड बेस के माध्यम से "बढ़ता" है। इसकी तुलना एक ज़ोंबी वायरस से की गई है । सबसे अच्छा समाधान यह है कि इसे बढ़ने दें, लेकिन कभी-कभी यह संभव नहीं है।
मैंने आंशिक रूप से अतुल्यकालिक कोड बेस से निपटने के लिए अपने Nito.AsyncEx लाइब्रेरी में कुछ प्रकार लिखे हैं । कोई समाधान नहीं है जो हर स्थिति में काम करता है, हालांकि।
समाधान ए
यदि आपके पास एक सरल अतुल्यकालिक विधि है जिसे इसके संदर्भ में वापस सिंक्रनाइज़ करने की आवश्यकता नहीं है, तो आप उपयोग कर सकते हैं Task.WaitAndUnwrapException
:
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
आप उपयोग नहीं करना चाहते हैं Task.Wait
या Task.Result
क्योंकि वे अपवादों को लपेटते हैं AggregateException
।
यह समाधान केवल तभी उपयुक्त है जब MyAsyncMethod
इसके संदर्भ में वापस सिंक्रनाइज़ नहीं किया जाता है। दूसरे शब्दों में, हर await
में MyAsyncMethod
साथ समाप्त होना चाहिए ConfigureAwait(false)
। इसका मतलब यह है कि यह किसी भी यूआई तत्वों को अद्यतन नहीं कर सकता है या ASP.NET अनुरोध संदर्भ तक नहीं पहुंच सकता है।
समाधान बी
यदि MyAsyncMethod
आपको इसके संदर्भ में वापस सिंक्रनाइज़ करने की आवश्यकता है, तो आप AsyncContext.RunTask
एक नेस्टेड संदर्भ प्रदान करने के लिए उपयोग करने में सक्षम हो सकते हैं :
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
* अद्यतन 4/14/2014: पुस्तकालय के हाल के संस्करणों में एपीआई इस प्रकार है:
var result = AsyncContext.Run(MyAsyncMethod);
( Task.Result
इस उदाहरण में उपयोग करना ठीक है क्योंकि अपवादों का RunTask
प्रचार होगा Task
)।
इसके AsyncContext.RunTask
बजाय आपको इसकी आवश्यकता हो सकती Task.WaitAndUnwrapException
है क्योंकि WinForms / WPF / SL / ASP.NET पर होने वाले एक सूक्ष्म गतिरोध की संभावना के कारण है:
- एक तुल्यकालिक विधि एक async विधि को बुलाती है, एक प्राप्त करना
Task
।
- सिंक्रोनस विधि पर एक अवरुद्ध प्रतीक्षा करता है
Task
।
async
विधि का उपयोग करता await
बिना ConfigureAwait
।
Task
इस स्थिति में पूरा नहीं कर सकते क्योंकि यह केवल पूरा करता है जब async
विधि समाप्त हो गया है; यह async
विधि पूर्ण नहीं हो सकती क्योंकि यह इसके निरंतरता को शेड्यूल करने का प्रयास कर रहा है SynchronizationContext
, और WinForms / WPF / SL / ASP.NET इस निरंतरता को चलाने की अनुमति नहीं देगा क्योंकि सिंक्रोनस विधि पहले से ही उस संदर्भ में चल रही है।
यह एक कारण है कि जितना संभव हो ConfigureAwait(false)
हर async
विधि के भीतर उपयोग करना एक अच्छा विचार है।
समाधान सी
AsyncContext.RunTask
हर परिदृश्य में काम नहीं करेगा। उदाहरण के लिए, यदि async
विधि ऐसी चीज़ का इंतजार करती है जिसके लिए UI ईवेंट को पूरा करने की आवश्यकता होती है, तो आप नेस्टेड संदर्भ के साथ भी गतिरोध करेंगे। उस स्थिति में, आप async
थ्रेड पूल पर विधि शुरू कर सकते हैं :
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
हालाँकि, इस समाधान के MyAsyncMethod
लिए थ्रेड पूल संदर्भ में काम करना होगा। इसलिए यह UI तत्वों को अपडेट नहीं कर सकता है या ASP.NET अनुरोध संदर्भ तक नहीं पहुंच सकता है। और उस स्थिति में, आप ConfigureAwait(false)
इसके await
कथनों में जोड़ सकते हैं , और समाधान ए का उपयोग कर सकते हैं।
अपडेट, 2019-05-01: वर्तमान "सबसे कम-सबसे खराब प्रथाएं" यहां एक एमएसडीएन लेख में हैं ।