2014-11-07 11 views
26

In C# Ich habe die folgenden zwei einfache Beispiele:.erwarten Task.Delay() vs. Task.Delay() Wait()

[Test] 
public void TestWait() 
{ 
    var t = Task.Factory.StartNew(() => 
    { 
     Console.WriteLine("Start"); 
     Task.Delay(5000).Wait(); 
     Console.WriteLine("Done"); 
    }); 
    t.Wait(); 
    Console.WriteLine("All done"); 
} 

[Test] 
public void TestAwait() 
{ 
    var t = Task.Factory.StartNew(async() => 
    { 
     Console.WriteLine("Start"); 
     await Task.Delay(5000); 
     Console.WriteLine("Done"); 
    }); 
    t.Wait(); 
    Console.WriteLine("All done"); 
} 

Das erste Beispiel erzeugt eine Aufgabe, die Drucke auf "Start", wartet 5 Sekunden lang druckt "Done" und beendet dann die Aufgabe. Ich warte bis die Aufgabe beendet ist und drucke dann "All done". Wenn ich den Test ausführe, funktioniert es wie erwartet.

Der zweite Test sollte das gleiche Verhalten haben, mit der Ausnahme, dass das Warten in der Task aufgrund der Verwendung von async nicht blockierend sein sollte und warten. Aber dieser Test druckt nur "Start" und dann sofort "All done" und "Done" wird nie gedruckt.

Ich weiß nicht, warum ich dieses Verhalten erhalten: S Jede Hilfe sehr geschätzt werden würde :)

+0

Task.Delay ist nicht blockierend. Ich sehe keinen Grund, warum Sie das 2. Konstrukt verwenden würden. –

+0

@RoyDictus haben beide ihre eigenen Probleme. Sie sollten niemals "Task.Wait()' – Gusdor

+0

mögliche Duplikate von [Warten auf async/erwarten in einer Aufgabe] (http://stackoverflow.com/questions/24777253/waiting-for-async-await-inside-a- Aufgabe) – i3arnon

Antwort

27

Der zweite Test hat zwei verschachtelte Aufgaben und Sie für die äußersten warten, um dieses Problem beheben Sie verwenden müssen, t.Result.Wait(). t.Result bekommt die innere Aufgabe.

Die zweite Methode entspricht in etwa dieser:

public void TestAwait() 
{ 
    var t = Task.Factory.StartNew(() => 
      { 
       Console.WriteLine("Start"); 
       return Task.Factory.StartNew(() => 
       { 
        Task.Delay(5000).Wait(); Console.WriteLine("Done"); 
       }); 
      }); 
      t.Wait(); 
      Console.WriteLine("All done"); 
} 

von t.Wait() Aufruf Sie äußerste Aufgabe warten, die sofort zurückgibt.


Der letztlich ‚richtige‘ Weg, um dieses Szenario zu behandeln ist mit Wait überhaupt zu verzichten und verwenden await nur. Wait kann deadlock issues verursachen, sobald Sie Ihrem asynchronen Code eine Benutzeroberfläche hinzugefügt haben.

[Test] 
    public async Task TestCorrect() //note the return type of Task. This is required to get the async test 'waitable' by the framework 
    { 
     await Task.Factory.StartNew(async() => 
     { 
      Console.WriteLine("Start"); 
      await Task.Delay(5000); 
      Console.WriteLine("Done"); 
     }).Unwrap(); //Note the call to Unwrap. This automatically attempts to find the most Inner `Task` in the return type. 
     Console.WriteLine("All done"); 
    } 

besser Auch nur Task.Run benutzen, um Ihre asynchronen Betrieb, kick off:

[TestMethod] 
    public async Task TestCorrect() 
    { 
     await Task.Run(async() => //Task.Run automatically unwraps nested Task types! 
     { 
      Console.WriteLine("Start"); 
      await Task.Delay(5000); 
      Console.WriteLine("Done"); 
     }); 
     Console.WriteLine("All done"); 
    } 
+2

Danke das funktioniert :) Übrigens ist es immer in Ordnung, Task.Run anstelle von Task.Factory.StartNew zu verwenden oder gibt es Fälle, in denen ich Task.Factory.StartNew benötigen würde, die Task.Run nicht verarbeiten kann? :) – svenskmand

+0

@svenskmand siehe http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx – brz