दिलचस्प पोस्ट
पायथन में समय बीत चुका है? जावास्क्रिप्ट में कई सरणियों का कार्टेशियन उत्पाद लोडिंग के साथ jqgrid reloadGrid को सही पर सेट करें SQL सर्वर अनुक्रमणिका – आरोही या अवरोही, यह क्या अंतर करता है? Std :: istream से एक अभिलेख स्ट्रक्चर फ़ील्ड को पढ़ना क्यों असफल है, और मैं इसे कैसे ठीक कर सकता हूं? यादृच्छिक सूची से कोई आइटम कैसे चुनें? मैं खिड़कियों के अनुप्रयोग में एक स्क्रीनशॉट कैसे ले सकता हूं? जावास्क्रिप्ट के साथ टेक्स्ट चौड़ाई की गणना करें अलग-अलग राज्य के लिए छवि बटन पृष्ठभूमि छवि कैसे सेट करें? दो सूचियों को शामिल करना – '+ =' के बीच का अंतर और विस्तार () आईओएस 10 – कैमरा, माइक्रोफ़ोन और फोटो लाइब्रेरी की अनुमति देने में परिवर्तन जिससे दुर्घटना के लिए आवेदन हो इकाई फ़्रेमवर्क 4 .NET में एक इकाई को कैसे अपडेट करें XML विशेषता में न्यूलाइन कैसे सहेज सकते हैं? क्या एंड्रॉइड पर अजगर चलाने का कोई तरीका है? त्रुटि: (23, 17) हल करने में असफल: जनीट: जनीट: 4.12

एक async विधि द्वारा फेंक दिया अपवाद पकड़ो

.NET के लिए async ctp का उपयोग करना, क्या कॉलिंग पद्धति में एक async विधि द्वारा फेंक दिया अपवाद को पकड़ना संभव है?

public async void Foo() { var x = await DoSomethingAsync(); /* Handle the result, but sometimes an exception might be thrown For example, DoSomethingAsync get's data from the network and the data is invalid... a ProtocolException might be thrown */ } public void DoFoo() { try { Foo(); } catch (ProtocolException ex) { /* The exception will never be caught Instead when in debug mode, VS2010 will warn and continue when deployed the app will simply crash. */ } } 

तो मूल रूप से मैं अपने कॉलिंग कोड में बुलबुला करने के लिए async कोड से अपवाद चाहता हूं, अगर यह बिल्कुल भी संभव है

वेब के समाधान से एकत्रित समाधान "एक async विधि द्वारा फेंक दिया अपवाद पकड़ो"

यह पढ़ने के लिए कुछ हद तक अजीब है, लेकिन हाँ, अपवाद कॉलिंग कोड पर बुलबुला होगा – लेकिन यह केवल तभी करेगा जब आप await या Wait() Foo को कॉल करें

 public async void DoFoo() { try { await Foo(); } catch (ProtocolException ex) { /* The exception will be caught because you've awaited the call. */ } } //or// public void DoFoo() { try { Foo().Wait(); } catch (ProtocolException ex) { /* The exception will be caught because you've awaited the call. */ } } 

ध्यान दें कि रुको () का उपयोग करने से आपका एप्लिकेशन अवरुद्ध हो सकता है, अगर नेट आपकी पद्धति को सिंक्रोनस तरीके से निष्पादित करने का निर्णय लेती है।

इस स्पष्टीकरण http://www.interact-sw.co.uk/iangblog/2010/11/01/csharp5-async-exceptions बहुत अच्छा है – यह उन संकल्पों पर चर्चा करता है जो संकलक इस जादू को प्राप्त करने के लिए करता है।

कारण अपवाद पकड़ा नहीं है क्योंकि फ़ू () विधि में एक शून्य वापसी प्रकार है और इसलिए जब प्रतीक्षा की जाती है, तो यह केवल रिटर्न देता है जैसा कि डूफू () फ़ू के पूरा होने का इंतजार नहीं कर रहा है, अपवाद हैंडलर का उपयोग नहीं किया जा सकता।

यह एक सरल समाधान को खोलता है यदि आप विधि हस्ताक्षर बदल सकते हैं – Foo() को बदल दें ताकि वह टाइप Task देता है और फिर DoFoo() इस कोड के रूप में await Foo() कर सकते हैं:

 public async Task Foo() { var x = await DoSomethingThatThrows(); } public async void DoFoo() { try { await Foo(); } catch (ProtocolException ex) { // This will catch exceptions from DoSomethingThatThrows } } 

आपका कोड ऐसा नहीं करता जो आपको लगता है। Async परिणाम की प्रतीक्षा करने के तरीके के रूप में Async विधियां तत्काल वापस आ जाएंगी। यह देखने के लिए कि क्या चल रहा है, यह सीखने के लिए शैक्षणिक है कि कैसे धागा इंटरैक्शन कर रहा है।

निम्नलिखित उदाहरण में मैं करता हूँ

  • 4 कार्य बनाएं
  • प्रत्येक कार्य एसिंक्रोनस संख्या को बढ़ाता है और बढ़ी हुई संख्या वापस करेगा
  • जब async परिणाम आ गया है यह पता लगाया है।

     static TypeHashes _type = new TypeHashes(typeof(Program)); private void Run() { TracerConfig.Reset("debugoutput"); using (Tracer t = new Tracer(_type, "Run")) { for (int i = 0; i < 4; i++) { DoSomeThingAsync(i); } } Application.Run(); // Start window message pump to prevent termination } private async void DoSomeThingAsync(int i) { using (Tracer t = new Tracer(_type, "DoSomeThingAsync")) { t.Info("Hi in DoSomething {0}",i); try { int result = await Calculate(i); t.Info("Got async result: {0}", result); } catch (ArgumentException ex) { t.Error("Got argument exception: {0}", ex); } } } Task<int> Calculate(int i) { var t = new Task<int>(() => { using (Tracer t2 = new Tracer(_type, "Calculate")) { if( i % 2 == 0 ) throw new ArgumentException(String.Format("Even argument {0}", i)); return i++; } }); t.Start(); return t; } 

जब आप निशान का निरीक्षण करते हैं

 22:25:12.649 02172/02820 { AsyncTest.Program.Run 22:25:12.656 02172/02820 { AsyncTest.Program.DoSomeThingAsync 22:25:12.657 02172/02820 Information AsyncTest.Program.DoSomeThingAsync Hi in DoSomething 0 22:25:12.658 02172/05220 { AsyncTest.Program.Calculate 22:25:12.659 02172/02820 { AsyncTest.Program.DoSomeThingAsync 22:25:12.659 02172/02820 Information AsyncTest.Program.DoSomeThingAsync Hi in DoSomething 1 22:25:12.660 02172/02756 { AsyncTest.Program.Calculate 22:25:12.662 02172/02820 { AsyncTest.Program.DoSomeThingAsync 22:25:12.662 02172/02820 Information AsyncTest.Program.DoSomeThingAsync Hi in DoSomething 2 22:25:12.662 02172/02820 { AsyncTest.Program.DoSomeThingAsync 22:25:12.662 02172/02820 Information AsyncTest.Program.DoSomeThingAsync Hi in DoSomething 3 22:25:12.664 02172/02756 } AsyncTest.Program.Calculate Duration 4ms 22:25:12.666 02172/02820 } AsyncTest.Program.Run Duration 17ms ---- Run has completed. The async methods are now scheduled on different threads. 22:25:12.667 02172/02756 Information AsyncTest.Program.DoSomeThingAsync Got async result: 1 22:25:12.667 02172/02756 } AsyncTest.Program.DoSomeThingAsync Duration 8ms 22:25:12.667 02172/02756 { AsyncTest.Program.Calculate 22:25:12.665 02172/05220 Exception AsyncTest.Program.Calculate Exception thrown: System.ArgumentException: Even argument 0 at AsyncTest.Program.c__DisplayClassf.Calculateb__e() in C:\Source\AsyncTest\AsyncTest\Program.cs:line 124 at System.Threading.Tasks.Task`1.InvokeFuture(Object futureAsObj) at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() 22:25:12.668 02172/02756 Exception AsyncTest.Program.Calculate Exception thrown: System.ArgumentException: Even argument 2 at AsyncTest.Program.c__DisplayClassf.Calculateb__e() in C:\Source\AsyncTest\AsyncTest\Program.cs:line 124 at System.Threading.Tasks.Task`1.InvokeFuture(Object futureAsObj) at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() 22:25:12.724 02172/05220 } AsyncTest.Program.Calculate Duration 66ms 22:25:12.724 02172/02756 } AsyncTest.Program.Calculate Duration 57ms 22:25:12.725 02172/05220 Error AsyncTest.Program.DoSomeThingAsync Got argument exception: System.ArgumentException: Even argument 0 Server stack trace: at AsyncTest.Program.c__DisplayClassf.Calculateb__e() in C:\Source\AsyncTest\AsyncTest\Program.cs:line 124 at System.Threading.Tasks.Task`1.InvokeFuture(Object futureAsObj) at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() Exception rethrown at [0]: at System.Runtime.CompilerServices.TaskAwaiter.EndAwait() at System.Runtime.CompilerServices.TaskAwaiter`1.EndAwait() at AsyncTest.Program.DoSomeThingAsyncd__8.MoveNext() in C:\Source\AsyncTest\AsyncTest\Program.cs:line 106 22:25:12.725 02172/02756 Error AsyncTest.Program.DoSomeThingAsync Got argument exception: System.ArgumentException: Even argument 2 Server stack trace: at AsyncTest.Program.c__DisplayClassf.Calculateb__e() in C:\Source\AsyncTest\AsyncTest\Program.cs:line 124 at System.Threading.Tasks.Task`1.InvokeFuture(Object futureAsObj) at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() Exception rethrown at [0]: at System.Runtime.CompilerServices.TaskAwaiter.EndAwait() at System.Runtime.CompilerServices.TaskAwaiter`1.EndAwait() at AsyncTest.Program.DoSomeThingAsyncd__8.MoveNext() in C:\Source\AsyncTest\AsyncTest\Program.cs:line 0 22:25:12.726 02172/05220 } AsyncTest.Program.DoSomeThingAsync Duration 70ms 22:25:12.726 02172/02756 } AsyncTest.Program.DoSomeThingAsync Duration 64ms 22:25:12.726 02172/05220 { AsyncTest.Program.Calculate 22:25:12.726 02172/05220 } AsyncTest.Program.Calculate Duration 0ms 22:25:12.726 02172/05220 Information AsyncTest.Program.DoSomeThingAsync Got async result: 3 22:25:12.726 02172/05220 } AsyncTest.Program.DoSomeThingAsync Duration 64ms 

आप देखेंगे कि रन विधि धागे 2880 पर पूर्ण होती है, जबकि केवल एक गणना दूसरे थ्रेड पर शुरू हुई है। यदि आप अपनी प्रतीक्षा पद्धति के आसपास एक प्रयास / पकड़ डालते हैं तो आप सामान्य तरीके से अपवाद को "पकड़" सकते हैं, हालांकि आपका कोड एक अन्य थ्रेड पर निष्पादित होता है जब गणना कार्य समाप्त हो जाता है और आपके परिचलन को निष्पादित किया जाता है।

गणना विधि स्वचालित रूप से फेंक दिया अपवाद का पता लगाता है क्योंकि मैं ApiChange.Api.dll को ApiChange टूल से उपयोग किया था। अनुरेखण और परावर्तक बहुत कुछ समझने में मदद करता है कि क्या हो रहा है। थ्रेडिंग से छुटकारा पाने के लिए आप GetAwaiter BeginAwait और EndAwait के अपने स्वयं के संस्करण बना सकते हैं और कोई कार्य नहीं लपेटें, लेकिन जैसे कि एक आलसी और अपने स्वयं के विस्तार विधियों के अंदर ट्रेस करें। तो आपको बेहतर समझ जाएगा कि कम्पाइलर और टीपीएल क्या करता है।

अब आप देखते हैं कि अपवाद वापस लेने का प्रयास करने के लिए कोई रास्ता नहीं है क्योंकि किसी भी अपवाद को छोड़ने के लिए कोई भी स्टाक फ्रेम नहीं है। आपके कोड में एसिंक ऑपरेशन आरंभ करने के बाद पूरी तरह से कुछ अलग हो सकता है यह थ्रेड को कॉल कर सकता है। जब तक एक अग्रभूमि धागा आपके आवेदन छोड़ दिया है, तब तक खुशी से अतुल्यकालिक कार्य निष्पादित करना जारी रहेगा।


आप अपने एसिंक्रोनस ऑपरेशन के समाप्त होने के बाद async विधि के अंदर अपवाद को नियंत्रित कर सकते हैं और UI थ्रेड में वापस कॉल कर सकते हैं। ऐसा करने का अनुशंसित तरीका TaskScheduler.FromSynchronizationContext के साथ है। यह केवल तभी काम करता है अगर आपके पास एक UI थ्रेड है और यह अन्य चीज़ों में बहुत व्यस्त नहीं है

तुम्हारा, एलोइस क्रॉस

यह भी नोट करना महत्वपूर्ण है कि आप अपवाद के कालानुक्रमिक स्टैक ट्रेस खो देंगे यदि आपके पास एक एसिंक विधि पर शून्य रिटर्न का प्रकार है मैं वापस लौटने की सिफारिश करेगा कार्य डीबगिंग को पूरी तरह से आसान बनाना

 public async Task DoFoo() { try { return await Foo(); } catch (ProtocolException ex) { /* Exception with chronological stack trace */ } } 

अपवाद को async फ़ंक्शन में पकड़ा जा सकता है।

 public async void Foo() { try { var x = await DoSomethingAsync(); /* Handle the result, but sometimes an exception might be thrown For example, DoSomethingAsync get's data from the network and the data is invalid... a ProtocolException might be thrown */ } catch (ProtocolException ex) { /* The exception will be caught here */ } } public void DoFoo() { Foo(); } 

यह ब्लॉग आपकी समस्या को बड़े करीने से असिनक बेस्ट प्रैक्टिस बताता है।

इसका सारांश यह है कि आपको एसिंक पद्धति की वापसी के रूप में शून्य का उपयोग नहीं करना चाहिए, जब तक कि यह एक एसिंक ईवेंट हैंडलर न हो, यह बुरा व्यवहार है क्योंकि यह अपवाद पकड़े जाने की अनुमति नहीं देता ;-)।

कार्य करने के लिए वापसी का तरीका बदलने के लिए सबसे अच्छा अभ्यास होगा साथ ही, async को सभी प्रकार की गर्तिका की कोशिश करें, हर async विधि कॉल करें और async विधियों से कॉल करें। कंसोल में मुख्य विधि को छोड़कर, जो async नहीं हो सकता

आप जीयूआई और एएसपी.NET अनुप्रयोगों के साथ डेडलॉक में चलाएंगे यदि आप इस सर्वोत्तम अभ्यास को अनदेखा करेंगे। डेडलॉक इसलिए होता है क्योंकि ये अनुप्रयोग एक संदर्भ पर चलते हैं जो केवल एक धागे की अनुमति देता है और इसे async धागा में त्याग नहीं करेगा। इसका अर्थ है कि जीयूआई वापसी के लिए तुल्यकालन की प्रतीक्षा करता है, जबकि एसिंक पद्धति संदर्भ के लिए प्रतीक्षा करता है: डेडलॉक

यह व्यवहार एक कंसोल अनुप्रयोग में नहीं होगा, क्योंकि यह एक थ्रेड पूल के साथ संदर्भ पर चलता है। Async विधि एक अन्य थ्रेड पर वापस आ जाएगी जो निर्धारित किया जाएगा। यही कारण है कि एक परीक्षण कंसोल ऐप काम करेगा, लेकिन एक ही कॉल अन्य अनुप्रयोगों में डेडलॉक होगा …