2015-09-04 11 views
15

मैं निम्नलिखित कोड में एक समस्या है:क्यों टास्क में भी खत्म इंतजार

static void Main (string[] args) 
{ 
    Task newTask = Task.Factory.StartNew(MainTask); 
    newTask.ContinueWith ((Task someTask) => 
    { 
     Console.WriteLine ("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted+" isComplete="+someTask.IsCompleted); 
    }); 
    while (true) 
    { 

    } 
} 

static async Task MainTask() 
{ 
    Console.WriteLine ("MainStarted!"); 
    Task someTask = Task.Factory.StartNew (() => 
    { 
     Console.WriteLine ("SleepStarted!"); 
     Thread.Sleep(1000); 
     Console.WriteLine ("SleepEnded!"); 
    }); 
    await someTask; 
    Console.WriteLine ("Waiting Ended!!"); 
    throw new Exception ("CustomException!"); 
    Console.WriteLine ("NeverReaches here!!"); 
} 

मैं सिर्फ नए शुरू कर दिया काम MainTask से अपवाद प्राप्त करना चाहते हैं। लेकिन नतीजा यह नहीं था कि मुझे क्या उम्मीद थी।

MainStarted! 
Main State = RanToCompletion IsFaulted = False isComplete = True 
SleepStarted! 
SleepEnded! 
Waiting Ended!! 

जैसा कि आप परिणाम देख सकते हैं, कार्य "प्रतीक्षा समाप्त हो गया !!" से पहले समाप्त होता है। कंसोल लॉग मेरे पास कोई सुराग नहीं है कि MainTask क्यों MainTask में await कमांड के अंदर भी समाप्त हुआ? क्या मुझे कुछ याद आया?

+0

कोई कारण नहीं है कि आप 'MainTask() नहीं कर सकते हैं।जारी रखें (...) 'सीधे? –

उत्तर

18

Task.Factory.StartNewdoes not understand async delegates इसलिए आपको इस मामले में Task.Run का उपयोग करने की आवश्यकता है और अपवाद का प्रवाह होना चाहिए।

Task.Factory.StartNew(MainTask); 

अनिवार्य रूप से

Task.Factory.StartNew(() => MainTask); 

जो MainTask से लौटे काम पर ध्यान नहीं देता और अपवाद सिर्फ निगल लिया हो जाता है के बराबर है।

अधिक जानकारी के लिए यह blog post देखें।

कोशिश के बजाय का उपयोग कर Task.Run और आप अपने अपवाद मिल जाएगा:

void Main(string[] args) 
{ 
    Task newTask = Task.Run(MainTask); 
    newTask.ContinueWith((Task someTask) => 
    { 
     Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted); 
    }); 
    while (true) 
    { 

    } 
} 

static async Task MainTask() 
{ 
    Console.WriteLine("MainStarted!"); 
    Task someTask = Task.Run(() => 
    { 
     Console.WriteLine("SleepStarted!"); 
     Thread.Sleep(1000); 
     Console.WriteLine("SleepEnded!"); 
    }); 
    await someTask; 
    Console.WriteLine("Waiting Ended!!"); 
    throw new Exception("CustomException!"); 
    Console.WriteLine("NeverReaches here!!"); 
} 
+0

@ मिकीडुनकन, इसे फिर से लिखने के लिए: "टास्क फैक्ट्री। स्टार्टन्यू एसिंक-जागरूक प्रतिनिधियों का समर्थन नहीं करता है। कार्य। रून करता है।" इसे देखें [ब्लॉग] (http://blog.stephencleary.com/2015/03/a-tour-of-task-part-9-delegate-tasks.html)। –

+0

शायद मुझे यह कहना चाहिए कि यह एसिंक प्रतिनिधियों को समझ में नहीं आता है। Http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html देखें –

1

मैं अपवाद को पकड़ने के लिए यहां आपकी समस्या को संशोधित।

static void Main(string[] args) 
    { 
     DoFoo(); 
     Console.ReadKey(); 
    } 



    static async void DoFoo() 
    { 
     try 
     { 
      await Foo(); 
     } 
     catch (Exception ex) 
     { 
      //This is where you can catch your exception 
     } 
    } 




    static async Task Foo() 
    { 

     await MainTask().ContinueWith((Task someTask) => 
     { 

      Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted); 

     }, TaskContinuationOptions.NotOnFaulted); 

    } 

    static async Task MainTask() 
    { 


     Console.WriteLine("MainStarted!"); 
     Task someTask = Task.Run(() => 
     { 
      Console.WriteLine("SleepStarted!"); 
      Thread.Sleep(1000); 
      Console.WriteLine("SleepEnded!"); 
     }); 
     await someTask; 
     throw new Exception("CustomException!"); 

     Console.WriteLine("Waiting Ended!!"); 


    } 

आप TaskContinuationOptions.NotOnFaulted का उपयोग करना चाहिए जिसका अर्थ है कि कार्य के साथ जारी रखने के लिए केवल निष्पादित करेंगे, तो माता-पिता काम किसी भी अपवाद नहीं किया था।

6

यहां बहुत अच्छे जवाब हैं, लेकिन मैं स्पष्ट करना चाहता हूं - Task.Factory.StartNew पूरी तरह से अनावश्यक, अनावश्यक और गलत है।

यदि आप

Task newTask = MainTask(); 

के साथ बदलें

Task newTask = Task.Factory.StartNew(MainTask); 

आप वास्तव में व्यवहार जैसा कि आप उम्मीद, बस एक और ThreadPool धागा शुरू करने के लिए अभी तक एक और ThreadPool धागे बर्बाद कर के बिना मिल जाएगा।

static void Main (string[] args) 
{ 
    var task = 
     MainTask() 
     .ContinueWith(t => Console.WriteLine("Main State={0}", t.Status)); 

    task.Wait(); 
} 

static async Task MainTask() 
{ 
    Console.WriteLine ("MainStarted!"); 

    await Task.Delay(1000); 

    Console.WriteLine ("Waiting Ended!!"); 

    throw new Exception ("CustomException!"); 

    Console.WriteLine ("NeverReaches here!!"); 
} 

इस कोड को केवल विलंब के बाद कोड के लिए एक धागा पूल धागा का उपयोग करता है, और पर अपवाद rethrows: वास्तव में, यदि आप और अधिक मुहावरेदार होने के लिए अपने उदाहरण के पुनर्लेखन के लिए चाहता था, आप कुछ इस तरह का उपयोग करें task.Wait() कॉल - आप निश्चित रूप से कुछ और करना चाहते हैं।

एक साइड-नोट के रूप में, भले ही आप कार्य को पूरा करने के लिए स्पष्ट रूप से इंतजार नहीं करना चाहते हैं, तो आपको आवेदन को रोकने से रोकने के लिए while (true) {} का उपयोग नहीं करना चाहिए - एक सरल Console.ReadLine() ठीक से काम करेगा, और नहीं आपके CPU कोर में से 100% उपयोग को धक्का नहीं दे रहा है :)

संबंधित मुद्दे