8

हमारे आवेदन में हम async/प्रतीक्षा और कार्य के साथ बहुत काम करते हैं। इसलिए यह कार्य का उपयोग करता है। बहुत सारे, कभी-कभी CancellationToken में निर्मित का उपयोग करके रद्दीकरण समर्थन के साथ।कार्य रद्द करने का प्रयास सफलता नियंत्रण प्रवाह पर अपवाद से कैसे बचें?

public Task DoSomethingAsync(CancellationToken cancellationToken) 
{ 
    return Task.Run(() => 
    { 
     while (true) 
     { 
      if (cancellationToken.IsCancellationRequested) break; 
      //do some work 
     } 
    }, cancellationToken); 
} 

मैं निष्पादन CancellationToken निष्पादन का उपयोग करके अगले पाश की शुरुआत में रोक है रद्द अब करते हैं, या यदि कार्य बिल्कुल शुरू नहीं किया यह एक अपवाद (Task.Run अंदर TaskCanceledException) फेंकता है। सवाल यह है कि टास्क.रुन एक पूर्ण कार्य को वापस करने के बजाय सफल रद्दीकरण को नियंत्रित करने के लिए अपवाद का उपयोग क्यों करता है। क्या कोई विशिष्ट कारण है कि एमएस "निष्पादन प्रवाह को नियंत्रित करने के लिए अपवादों का उपयोग न करें" नियम से चिपके नहीं है?

और मैं पूरी तरह से बेकार प्रयास पकड़ (टास्क कैंक्ड एक्सेप्शन) ब्लॉक में रद्दीकरण (जो बहुत कुछ है) का समर्थन करने वाली हर विधि को बॉक्सिंग से कैसे बच सकता हूं?

+2

"-

हालांकि, अगर आप TaskCanceledException व्यवहार पर अधिक नियंत्रण है चाहते हैं और अभी भी तर्क एक जगह पर अलग-थलग है आप जो रद्द संभालती Task विस्तार करने के लिए एक विस्तार विधि, कुछ इस तरह लागू कर सकते हैं रद्दीकरण! = सफल समापन "। रद्द होने पर वापस आने के लिए 'कार्य ' की अपेक्षा क्या होगी? –

+0

** कार्य रद्द करने के साथ रद्द किया गया एक कार्य उदाहरण TokenSource.Cancel(); ** ** टास्कस्टैटस। RanToCompletion State ** होगा, ** टास्कस्टैटस के लिए नहीं। रद्द ** राज्य। –

+0

आप वापसी मूल्य के साथ कार्य के लिए सही हैं अपवाद की आवश्यकता है। इसके बारे में सोचा नहीं था। – Console

उत्तर

5

ठीक है, आप वास्तव में अपने बहुत ही सरल परिदृश्य में अंतर नहीं देख सकते हैं - आप वास्तव में Task के परिणाम का उपयोग नहीं कर रहे हैं, और आपको जटिल कॉल स्टैक के माध्यम से रद्दीकरण को प्रसारित करने की आवश्यकता नहीं है।

सबसे पहले, आपके Task एक मूल्य वापस कर सकता है। ऑपरेशन रद्द होने पर आप क्या लौटते हैं?

दूसरा, आपके रद्द किए गए कार्य का पालन करने वाले अन्य कार्य भी हो सकते हैं। आप शायद अपनी सुविधा पर अन्य कार्यों के माध्यम से रद्दीकरण का प्रचार करना चाहते हैं।

अपवाद प्रचार। इस उपयोग में कार्य रद्दीकरण Thread.Abort के बराबर समान है - जब आप Thread.Abort जारी करते हैं, तो ThreadAbortException का उपयोग यह सुनिश्चित करने के लिए किया जाता है कि आप शीर्ष पर वापस जाने के लिए सभी तरह से अनदेखा करें। अन्यथा, आपके सभी तरीकों को उनके द्वारा कॉल की जाने वाली प्रत्येक विधि के परिणाम की जांच करनी होगी, जांचें कि क्या उन्हें रद्द कर दिया गया है, और यदि आवश्यक हो तो खुद को वापस कर दें - और हमने पहले ही देखा है कि लोग पुराने स्कूल सी में त्रुटि वापसी मानों को अनदेखा करेंगे :)

अंत में, थ्रेड एबॉर्ट्स की तरह कार्य रद्दीकरण एक असाधारण परिदृश्य है। इसमें पहले से ही सिंक्रनाइज़ेशन, अवांछित ढेर इत्यादि शामिल हैं

हालांकि, इसका मतलब यह नहीं है कि आपको अपवाद को पकड़ने के लिए try-catch का उपयोग करना होगा - आप कार्य राज्यों का उपयोग कर सकते हैं। उदाहरण के लिए, अगर आप इस तरह एक सहायक समारोह का उपयोग कर सकते हैं:

public static Task<T> DefaultIfCanceled<T>(this Task<T> @this, T defaultValue = default(T)) 
{ 
    return 
    @this.ContinueWith 
     (
     t => 
     { 
      if (t.IsCanceled) return defaultValue; 

      return t.Result; 
     } 
    ); 
} 

रूप

await SomeAsync().DefaultIfCanceled(); 
बेशक

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

(*) अस्वीकरण: हमारे पास वास्तव में कुकीज़ नहीं है। लेकिन आप अपना खुद का बना सकते हैं!

0

अपवाद को किसी उद्देश्य के लिए फेंक दिया गया है क्योंकि समुदाय के अन्य लोगों ने इसे पहले ही इंगित कर दिया है।

public async Task DoSomethingAsync(CancellationToken cancellationToken) 
    { 
     await Task.Run(() => 
     { 
      while (true) 
      { 
       if (cancellationToken.IsCancellationRequested) break; 
       //do some work 
      } 
     }). 
     WithCancellation(cancellationToken,false); // pass the cancellation token to extension funciton instead to run 
    } 



static class TaskCacellationHelper 
{ 
    private struct Void { } // just to support TaskCompletionSource class. 


    public static async Task WithCancellation(this Task originalTask, CancellationToken ct, bool suppressCancellationExcetion) 
    { 
     // Create a Task that completes when the CancellationToken is canceled 
     var cancelTask = new TaskCompletionSource<Void>(); 
     // When the CancellationToken is canceled, complete the Task 
     using (ct.Register(
     t => ((TaskCompletionSource<Void>)t).TrySetResult(new Void()), cancelTask)) 
     { 
      // Create a Task that completes when either the original or 
      // CancellationToken Task completes 
      Task any = await Task.WhenAny(originalTask, cancelTask.Task); 
      // If any Task completes due to CancellationToken, throw OperationCanceledException 
      if (any == cancelTask.Task) 
      { 
       // 
       if (suppressCancellationExcetion == false) 
       { 
        ct.ThrowIfCancellationRequested(); 
       } 
       else 
       { 
        Console.WriteLine("Cancelled but exception supressed"); 
       } 
      } 
     } 
     // await original task. Incase of cancellation your logic will break the while loop    
     await originalTask; 
    } 
} 
संबंधित मुद्दे