it-swarm.com.de

warten Task.Delay () vs. Task.Delay (). Warten ()

In C # habe ich die folgenden zwei einfachen Beispiele:

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

Im ersten Beispiel wird eine Aufgabe erstellt, die "Start" ausgibt, 5 Sekunden auf "Fertig" wartet und dann die Aufgabe beendet. Ich warte, bis die Aufgabe abgeschlossen ist, und drucke dann "Alles erledigt". Wenn ich den Test durchführe, funktioniert er wie erwartet.

Der zweite Test sollte dasselbe Verhalten aufweisen, mit der Ausnahme, dass das Warten innerhalb des Tasks aufgrund der Verwendung von Async und Warten nicht blockiert werden sollte. Bei diesem Test wird jedoch nur "Start" und dann sofort "Alles erledigt" gedruckt, und "Fertig" wird nie gedruckt.

Ich weiß nicht, warum ich dieses Verhalten bekomme: S Jede Hilfe wäre sehr dankbar :)

45
svenskmand

Der zweite Test hat zwei verschachtelte Aufgaben und Sie warten auf die äußerste Aufgabe. Um dies zu beheben, müssen Sie t.Result.Wait() verwenden. t.Result Bekommt die innere Aufgabe.

Die zweite Methode ist ungefähr gleichbedeutend damit:

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

Wenn Sie t.Wait() aufrufen, warten Sie auf die äußerste Aufgabe, die sofort zurückkehrt.


Die letztendlich 'richtige' Art, mit diesem Szenario umzugehen, besteht darin, auf die Verwendung von Wait zu verzichten und nur await zu verwenden. Wait kann Deadlock-Probleme verursachen, sobald Sie eine Benutzeroberfläche an Ihren asynchronen Code angehängt 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");
    }

Verwenden Sie noch besser Task.Run, Um Ihre asynchrone Operation zu starten:

    [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");
    }
43
brz