टास्क है। गुलाल के रूप में ही है।


328

मैं हाल ही में कुछ कोड पढ़ रहा था जो बहुत से एस्किंस विधियों का उपयोग करता है, लेकिन फिर कभी-कभी उन्हें तुल्यकालिक रूप से निष्पादित करने की आवश्यकता होती है। कोड करता है:

Foo foo = GetFooAsync(...).GetAwaiter().GetResult();

क्या यह भी ऐसा ही है

Foo foo = GetFooAsync(...).Result;

8
डॉक्स से GetResult: "यह प्रकार और इसके सदस्यों को संकलक द्वारा उपयोग करने के लिए अभिप्रेत है।" अन्य व्यक्ति को इसका उपयोग नहीं करना चाहिए।
२१:३१

32
इसे "async पर सिंक" कहा जाता है, और जब तक आप नहीं जानते कि कार्य कैसे कार्यान्वित किया जाता है, वास्तव में एक बुरा विचार हो सकता है। यह तुरंत कई मामलों में गतिरोध कर सकते हैं (एक async/ awaitMVC में विधि, उदाहरण के लिए)
मार्क Gravell


14
वास्तविक दुनिया में, हमारे पास निर्माणकर्ता हैं, हमारे पास "कोई प्रतीक्षा नहीं" इंटरफेस है जिसे हमें लागू करने की आवश्यकता है, और हमें हर जगह async तरीके दिए गए हैं। मुझे ऐसी किसी चीज़ का उपयोग करने में प्रसन्नता होगी जो मेरे बिना काम करती है और मुझे आश्चर्य होता है कि यह "खतरनाक", "उपयोग नहीं किया जाना" या "हर कीमत पर टालना" है। हर बार जब मुझे async के साथ गड़बड़ करना पड़ता है तो सिरदर्द हो जाता है।
लैरी

जवाबों:


173

बहुत ज्यादा। एक छोटा अंतर हालांकि: यदि Taskविफल रहता है, GetResult()तो केवल अपवाद को सीधे Task.Resultफेंक देगा , जबकि फेंक देगा AggregateException। हालाँकि, जब उनमें से किसी एक का उपयोग करने का क्या मतलब है async? 100x बेहतर विकल्प का उपयोग करना है await

इसके अलावा, आप उपयोग करने के लिए नहीं हैं GetResult()। यह संकलक उपयोग के लिए ही है, आपके लिए नहीं है। लेकिन अगर आप कष्टप्रद नहीं चाहते हैं AggregateException, तो इसका उपयोग करें।


27
@JayBazuzi नहीं यदि आपकी इकाई परीक्षण ढाँचा async इकाई परीक्षणों का समर्थन करता है, जो मुझे लगता है कि अधिकांश चौखटों के नवीनतम संस्करण हैं।
20

15
@JayBazuzi: MSTest, xUnit, और NUnit सभी समर्थन async Taskइकाई परीक्षण, और अभी कुछ समय के लिए है।
स्टीफन क्लीयर

18
100x पर वापस धकेलना - यदि आप पुराने कोड को स्वीकार कर रहे हैं और प्रतीक्षा का उपयोग कर रहे हैं तो उसे फिर से लिखने के लिए 1000x बदतर है।
अटक गया


15
The 100x better option is to use await.मुझे इस तरह के बयानों से नफरत है, अगर मैं इसके awaitसामने थप्पड़ मार सकता था । लेकिन, जब मैं गैर-एस्किंक कोड के खिलाफ काम करने के लिए async कोड प्राप्त करने की कोशिश कर रहा हूं, जैसे कि Xamarin में अक्सर मेरे साथ बहुत कुछ होता है , तो मैं ContinueWithयूआई को गतिरोध नहीं बनाने के लिए बहुत सी चीजों का उपयोग करने के लिए समाप्त होता हूं । संपादित करें: मुझे पता है कि यह पुराना है, लेकिन यह मेरी हताशा को कम करने का जवाब नहीं देता है जो उन स्थितियों के लिए कोई विकल्प नहीं है, जहां आप इसका उपयोग नहीं कर सकते हैं await
थॉमस एफ।

147

Task.GetAwaiter().GetResult()अधिक पसंद किया जाता है Task.Waitऔर Task.Resultक्योंकि यह अपवादों को एक में लपेटने के बजाय प्रचारित करता है AggregateException। हालांकि, सभी तीन विधियां गतिरोध और थ्रेड पूल भुखमरी के मुद्दों की क्षमता का कारण बनती हैं। इन सबके पक्ष में टाला जाना चाहिए async/await

नीचे बोली क्यों बताते हैं Task.Waitऔर Task.Resultबस के अपवाद के प्रचार व्यवहार शामिल नहीं है Task.GetAwaiter().GetResult()(एक "बहुत ही उच्च संगतता बार" के कारण)।

जैसा कि मैंने पहले उल्लेख किया है, हमारे पास एक बहुत ही उच्च संगतता पट्टी है, और इस प्रकार हमने परिवर्तनों को तोड़ने से बचा लिया है। जैसे, Task.Waitहमेशा लपेटने के अपने मूल व्यवहार को बरकरार रखता है। हालाँकि, आप अपने आप को कुछ उन्नत स्थितियों में पा सकते हैं, जहाँ आप अपने द्वारा नियोजित तुल्यकालिक अवरोधन के समान व्यवहार चाहते हैं Task.Wait, लेकिन जहाँ आप चाहते हैं कि मूल अपवाद एक में संलग्न होने की बजाय अलिखित प्रचारित हो AggregateException। इसे प्राप्त करने के लिए, आप सीधे टास्क के वेटर को लक्षित कर सकते हैं। जब आप " await task;" लिखते हैं , तो संकलक उस Task.GetAwaiter()विधि के उपयोग में अनुवाद करता है , जो एक उदाहरण देता है जिसमें एक GetResult()विधि होती है। जब एक दोषपूर्ण कार्य पर उपयोग किया जाता है, GetResult()तो मूल अपवाद का प्रचार करेगा (यह इस तरह से है " await task;" अपने व्यवहार को प्राप्त करता है)। आप इस प्रकार उपयोग कर सकते हैं ”task.GetAwaiter().GetResult()“यदि आप इस प्रचार तर्क को सीधे लागू करना चाहते हैं।

https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

" GetResultवास्तव में इसका मतलब है" त्रुटियों के लिए कार्य की जांच करें "

सामान्य तौर पर, मैं एक अतुल्यकालिक कार्य पर तुल्यकालिक रूप से अवरुद्ध होने से बचने की पूरी कोशिश करता हूं। हालाँकि, ऐसी कई परिस्थितियाँ हैं जहाँ मैं उस दिशानिर्देश का उल्लंघन करता हूँ। उन दुर्लभ परिस्थितियों में, मेरा पसंदीदा तरीका है GetAwaiter().GetResult()क्योंकि यह कार्य अपवादों को एक में लपेटने के बजाय सुरक्षित रखता है AggregateException

http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html


3
तो मूल रूप Task.GetAwaiter().GetResult()से के बराबर है await task। मुझे लगता है कि पहला विकल्प का उपयोग तब किया जाता है जब विधि को चिह्नित नहीं किया जा सकता है async(उदाहरण के लिए निर्माता)। क्या वो सही है? यदि हाँ, तो यह शीर्ष उत्तर @ ItNotALie से टकराता है
ओलेगआई

5
@ ऑली: के Task.GetAwaiter().GetResult()बराबर है ( Task.Waitऔर इसमें Task.Resultतीनों समकालिक रूप से ब्लॉक हो जाएंगे और गतिरोध की क्षमता होगी), लेकिन Task.GetAwaiter().GetResult()प्रतीक्षा कार्य का अपवाद प्रसार व्यवहार है।
नितिन अग्रवाल

क्या आप इस कार्य (कार्य) के साथ इस परिदृश्य में गतिरोध से बच नहीं सकते हैं ।ConfigureAwait (गलत) .GetAwaiter ()। GetResult (); ?
डैनियल लॉरेंज

3
@DanielLorenz: निम्न उद्धरण देखें: "डेडलॉक से बचने के लिए कन्फ़िगरएविट (झूठे) का उपयोग करना एक खतरनाक अभ्यास है। आपको ब्लॉकिंग कोड द्वारा कहे जाने वाले सभी तरीकों के सकर्मक बंद होने की प्रतीक्षा में कॉन्फिगरएविट (गलत) का उपयोग करना होगा, जिसमें सभी तीसरे भी शामिल हैं। - और दूसरे पक्ष के कोड। गतिरोध से बचने के लिए कन्फिगरएविट (झूठे) का उपयोग करना सबसे अच्छा हैक है।) ... बेहतर उपाय यह है कि "async कोड को ब्लॉक न करें"। " - blog.stephencleary.com/2012/07/dont-block-on-async-code.html
नितिन अग्रवाल

4
मुझे नहीं मिला। Task.Wait और Task.esult डिजाइन से टूट गए हैं? वे अप्रचलित क्यों नहीं हैं?
osexpert

69

https://github.com/aspnet/Security/issues/59

"एक अंतिम टिप्पणी: आपको उपयोग करने से बचना चाहिए Task.Resultऔर Task.Waitजितना संभव हो उतना संभव है कि वे हमेशा आंतरिक अपवाद को एक में संलग्न करते हैं AggregateExceptionऔर संदेश को एक जेनेरिक एक (एक या अधिक त्रुटियां हुई) द्वारा प्रतिस्थापित करते हैं, जो डीबगिंग को कठिन बनाता है। भले ही तुल्यकालिक संस्करण को चाहिए। "अक्सर ऐसा नहीं किया जाना चाहिए, आपको Task.GetAwaiter().GetResult()इसके बजाय दृढ़ता से उपयोग करने पर विचार करना चाहिए ।"


20
यहां जिस स्रोत का संदर्भ दिया गया है, वह कोई और व्यक्ति है, बिना किसी संदर्भ के। संदर्भ पर विचार करें: मैं इसे पढ़ने के बाद हर जगह GetAwaiter ()। GetResult () का उपयोग करके नेत्रहीन लोगों को देख सकता हूं।
जैक उलेजा

2
इसलिए हमें इसका उपयोग नहीं करना चाहिए?
टॉफूटिम

11
यदि दो कार्य अपवाद के साथ समाप्त होते हैं, तो आप इस परिदृश्य में दूसरे को ढीला कर देंगे Task.WhenAll(task1, task2).GetAwaiter().GetResult();
मोनसिग्नर

यहाँ एक और उदाहरण है: github.com/aspnet/AspNetCore/issues/13611
जॉर्ज चाकीदेज़

33

एक और अंतर यह है कि जब asyncफ़ंक्शन वापस आता Taskहै Task<T>तो उसके बजाय आप उपयोग नहीं कर सकते

GetFooAsync(...).Result;

जहाँ तक

GetFooAsync(...).GetAwaiter().GetResult();

अभी भी काम करता है।

मुझे पता है कि प्रश्न में उदाहरण कोड मामले के लिए है Task<T>, हालांकि प्रश्न आम तौर पर पूछा जाता है।


1
यह सच नहीं है। : मेरे बेला जो वास्तव में इस संरचना का भी उपयोग की जाँच करें dotnetfiddle.net/B4ewH8
wojciech_rak

3
अपने कोड में @wojciech_rak, आप उपयोग कर रहे Resultसाथ GetIntAsync()जो रिटर्न Task<int>न सिर्फ Task। मेरा सुझाव है कि आप मेरे उत्तर को फिर से पढ़ें।
नूरी तसदीम

1
आप सही हैं, पहले तो मुझे समझ में आया कि आप जवाब देते हैं कि आप किसी ऐसे फ़ंक्शन के GetFooAsync(...).Result अंदर नहीं जा सकते जो वापस आए Task। यह अब समझ में आता है, क्योंकि C # में कोई शून्य गुण नहीं है ( Task.Resultएक संपत्ति है), लेकिन आप निश्चित रूप से एक शून्य विधि कह सकते हैं।
wojciech_rak

22

जैसा कि पहले ही उल्लेख किया गया है यदि आप उपयोग कर सकते हैं await। यदि आपको कोड को समान रूप से चलाने की आवश्यकता है जैसा कि आप उल्लेख करते हैं .GetAwaiter().GetResult(), .Resultया .Wait()गतिरोध के लिए एक जोखिम है जैसा कि कई ने टिप्पणी / उत्तर में कहा है। चूँकि हम में से अधिकांश लोग ओनलिनर्स पसंद करते हैं, इसलिए आप इनका उपयोग कर सकते हैं.Net 4.5<

एक async विधि के माध्यम से एक मूल्य प्राप्त करना:

var result = Task.Run(() => asyncGetValue()).Result;

एसिंक्रोनस तरीके से कॉल करना

Task.Run(() => asyncMethod()).Wait();

के उपयोग के कारण कोई गतिरोध के मुद्दे नहीं होंगे Task.Run

स्रोत:

https://stackoverflow.com/a/32429753/3850405


1

यदि कोई कार्य दोष है, तो अपवाद पुन: फेंका जाता है जब निरंतरता कोड प्रतीक्षाकर्ता को कॉल करता है। GetResult ()। GetResult को कॉल करने के बजाय, हम केवल कार्य के परिणाम की संपत्ति तक पहुँच सकते हैं। GetResult को कॉल करने का लाभ यह है कि यदि कार्य दोष होता है, तो अपवाद को सीधे एग्रीग्रेटएक्सपेप्शन में लपेटे बिना ही फेंक दिया जाता है, जो सरल और क्लीनर को पकड़ने वाले ब्लॉक के लिए अनुमति देता है।

नौसिखिया कार्यों के लिए, GetResult () में एक शून्य वापसी मूल्य है। इसका उपयोगी कार्य केवल अपवादों को पुनर्विचार करना है।

स्रोत: सी # 7.0 एक संक्षेप में

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