2015-09-04 8 views
15

ich ein Problem im folgenden Code habe:Warum Aufgabe endet sogar in warten

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!!"); 
} 

Ich mag nur MainTask Ausnahme von neuem gestarteter Aufgabe zu bekommen. Aber das Ergebnis war nicht das, was ich erwartet hatte.

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

Wie Sie das Ergebnis sehen können, beendet Aufgabe vor „Ended Warten !!“ Konsolenprotokoll Ich habe keine Ahnung, warum MainTask endete auch wenn in MainTask hat await Befehl innen? Habe ich etwas verpasst?

+0

Jeder Grund, warum Sie 'MainTask() nicht tun können.Fortfahren mit (...) 'direkt? –

Antwort

18

Task.Factory.StartNewdoes not understand async delegates so müssen Sie in diesem Fall Task.Run verwenden und die Ausnahme sollte durchlaufen.

Task.Factory.StartNew(MainTask); 

ist im wesentlichen äquivalent zu

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

die die zurück Aufgabe aus MainTask ignoriert und die Ausnahme wird nur geschluckt.

Weitere Informationen finden Sie unter blog post.

Versuchen Sie es mit Task.Run statt und Sie werden Ihre Ausnahme erhalten:

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

@MickyDuncan, umzuformulieren: "TaskFactory.StartNew unterstützt keine async-bewussten Delegaten. Task.Run tut." Siehe hierzu [Blog] (http://blog.stephencleary.com/2015/03/a-tour-of-task-part-9-delegate-tasks.html). –

+0

Vielleicht sollte ich sagen, dass es asynchrone Delegierte nicht versteht. Siehe http://blog.stephencleary.com/2013/08/startnew-dangerous.html –

1

ich geändert hier Ihr Problem, die Ausnahmen zu fangen.

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!!"); 


    } 

sollten Sie TaskContinuationOptions.NotOnFaulted verwenden, was bedeutet, dass die mit Aufgabe fortsetzen wird nur ausgeführt, wenn die übergeordnete Aufgabe alle Ausnahmen nicht gehabt haben.

6

Hier gibt es gute Antworten, aber ich möchte auf das Offensichtliche hinweisen - das Task.Factory.StartNew ist komplett redundant, unnötig und falsch verwendet.

Wenn Sie

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

mit

Task newTask = MainTask(); 

ersetzen werden Sie erhalten genau das Verhalten, das Sie erwarten, ohne nur noch einen Threadpool-Thread zu verschwenden andere Thread Thread zu starten. In der Tat, wenn Sie Ihr Beispiel umschreiben wollte mehr idiomatische, würden Sie so etwas wie folgt verwenden: auf

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!!"); 
} 

Dieser Code verwendet nur einen Thread-Pool-Thread für den Code nach der Verzögerung, und rethrows die Ausnahme die task.Wait() Anruf - Sie möchten natürlich etwas anderes tun.

Als Randnotiz, auch wenn Sie nicht wollen, explizit für die Aufgabe warten, zu vervollständigen, sollten Sie nicht while (true) {} verwenden, um die Anwendung von beendet zu verhindern - ein einfachen Console.ReadLine() wird genauso gut funktionieren, und isn Ich werde einen Ihrer CPU-Kerne auf 100% Auslastung schieben :)

Verwandte Themen