web-dev-qa-db-ger.com

Was ist der Unterschied zwischen Task.Start / Wait und Async / Await?

Möglicherweise fehlt mir etwas, aber was ist der Unterschied zwischen:

public void MyMethod()
{
  Task t = Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();
  UpdateLabelToSayItsComplete();
}

public async void MyMethod()
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  UpdateLabelToSayItsComplete();
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}
203
Jon

Ich kann etwas vermissen

Sie sind.

was ist der Unterschied zwischen Task.Wait und await task?

Sie bestellen Ihr Mittagessen beim Kellner im Restaurant. Einen Moment nach Ihrer Bestellung kommt ein Freund herein, setzt sich neben Sie und beginnt ein Gespräch. Jetzt haben Sie zwei Möglichkeiten. Sie können Ihren Freund ignorieren, bis die Aufgabe erledigt ist - Sie können warten, bis Ihre Suppe eintrifft, und nichts anderes tun, während Sie warten. Oder Sie können Ihrem Freund antworten, und wenn Ihr Freund aufhört zu reden, bringt Ihnen der Kellner Ihre Suppe.

Task.Wait blockiert, bis die Aufgabe abgeschlossen ist - Sie ignorieren Ihren Freund, bis die Aufgabe abgeschlossen ist. await verarbeitet weiterhin Nachrichten in der Nachrichtenwarteschlange. Wenn die Aufgabe abgeschlossen ist, wird eine Nachricht mit der Aufschrift "Abholen, wo Sie danach aufgehört haben" in die Warteschlange gestellt. Sie sprechen mit Ihrem Freund, und wenn das Gespräch unterbrochen wird, kommt die Suppe.

385
Eric Lippert

Um die Antwort von Eric zu demonstrieren, ist hier ein Code:

public void ButtonClick(object sender, EventArgs e)
{
  Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();  
  //If you press Button2 now you won't see anything in the console 
  //until this task is complete and then the label will be updated!
  UpdateLabelToSayItsComplete();
}

public async void ButtonClick(object sender, EventArgs e)
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  //If you press Button2 now you will see stuff in the console and 
  //when the long method returns it will update the label!
  UpdateLabelToSayItsComplete();
}

public void Button_2_Click(object sender, EventArgs e)
{
  Console.WriteLine("Button 2 Clicked");
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}
117
Jon

Dieses Beispiel zeigt den Unterschied sehr deutlich. Mit async/await blockiert der aufrufende Thread nicht und setzt die Ausführung fort.

static void Main(string[] args)
{
    WriteOutput("Program Begin");
    // DoAsTask();
    DoAsAsync();
    WriteOutput("Program End");
    Console.ReadLine();
}

static void DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    t.Wait();
    WriteOutput("3 - Task completed with result: " + t.Result);
}

static async Task DoAsAsync()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    var result = await t;
    WriteOutput("3 - Task completed with result: " + result);
}

static int DoSomethingThatTakesTime()
{
    WriteOutput("A - Started something");
    Thread.Sleep(1000);
    WriteOutput("B - Completed something");
    return 123;
}

static void WriteOutput(string message)
{
    Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message);
}

DoAsTask-Ausgabe:

 [1] Programmstart 
 [1] 1 - Start von 
 [1] 2 - Aufgabe gestartet 
 [3] A - Start von etwas 
 [3] B - Etwas erledigt 
 [1] 3 - Aufgabe erledigt mit Ergebnis: 123 
 [1] Programmende 

DoAsAsync-Ausgabe:

 [1] Programmstart 
 [1] 1 - Start von 
 [1] 2 - Aufgabe gestartet 
 [3] A - Start von etwas 
 [1] Programmende 
 [3] B - Etwas erledigt 
 [3] 3 - Aufgabe erledigt mit Ergebnis: 123 

pdate: Verbessertes Beispiel durch Anzeigen der Thread-ID in der Ausgabe.

45
Mas

Wait () führt dazu, dass möglicherweise asynchroner Code synchron ausgeführt wird. erwarten wird nicht.

Sie haben beispielsweise eine asp.net-Webanwendung. UserA ruft den Endpunkt/getUser/1 auf. Der asp.net-App-Pool wählt einen Thread aus dem Thread-Pool (Thread1) aus und dieser Thread führt einen http-Aufruf durch. Wenn Sie Wait () ausführen, wird dieser Thread blockiert, bis der http-Aufruf aufgelöst ist. Wenn UserB während der Wartezeit/getUser/2 aufruft, muss der App-Pool einen anderen Thread (Thread2) bedienen, um den http-Aufruf erneut auszuführen. Sie haben gerade einen anderen Thread erstellt (der eigentlich aus dem App-Pool abgerufen wurde), und zwar ohne Grund, da Sie Thread1 nicht verwenden können. Dieser wurde von Wait () blockiert.

Wenn Sie wait für Thread1 verwenden, verwaltet SyncContext die Synchronisierung zwischen Thread1 und http-Aufruf. Es wird einfach benachrichtigt, sobald der http-Aufruf abgeschlossen ist. Wenn UserB/getUser/2 aufruft, werden Sie Thread1 erneut verwenden, um einen http-Aufruf zu tätigen, da er veröffentlicht wurde, sobald er auf einen Treffer wartet. Dann kann eine andere Anfrage es noch weiter nutzen. Sobald der http-Aufruf abgeschlossen ist (Benutzer1 oder Benutzer2), kann Thread1 das Ergebnis abrufen und zum Aufrufer (Client) zurückkehren. Thread1 wurde für mehrere Aufgaben verwendet.

9
Teoman shipahi

In diesem Beispiel praktisch nicht viel. Wenn Sie auf eine Task warten, die in einem anderen Thread zurückgegeben wird (z. B. einem WCF-Aufruf) oder die Steuerung an das Betriebssystem übergibt (z. B. File IO), wird wait weniger Systemressourcen verbrauchen, indem kein Thread blockiert wird.

9
foson

Im obigen Beispiel können Sie "TaskCreationOptions.HideScheduler" verwenden und die "DoAsTask" -Methode stark ändern. Die Methode selbst ist nicht asynchron, wie dies bei "DoAsAsync" der Fall ist, da sie einen "Task" -Wert zurückgibt und als "async" markiert ist, wobei mehrere Kombinationen vorgenommen werden. Dies entspricht genau der Verwendung von "async/await". :

static Task DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic

    TaskCompletionSource<int> tsc = new TaskCompletionSource<int>();
    t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task

    WriteOutput("2 - Task started");

    tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task
    return tsc.Task;
}
3
user8545699