8 Stimmen

Wenn die Methode "void" zurückgibt, ist das dasselbe wie eine Aufgabe (task)?

Ich versuche die async CTP, die Version 4.5, die es ermöglicht, async Methoden zu verwenden, ohne die Begin/End Methoden schreiben zu müssen.

Meine erste Probe ist die Ausführung einer async Methode, die void zurückgibt. Ich sehe ein paar Beispiele und mache folgendes:

private void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("Klick auf die Schaltfläche: " + System.DateTime.Now);
    method01Async();
    UpdateTxtLog("nach ethod01Async: " + System.DateTime.Now);
}

private async void method01Async()
{
    await TaskEx.Run(() =>
    {
        UpdateTxtLog("Betritt method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("Verlassen von method01Async: " + System.DateTime.Now);
    });
}

In meinem WPF-Projekt habe ich ein TextBox, in dem ich die Ergebnisse sehe, und eine Schaltfläche, die die async Methode ausführt.

In der async Methode verwende ich await, was nötig ist, da die Methode async ist, und TaskEx.Run, um einen neuen Thread zu erstellen, in dem der Code ausgeführt wird.

Meine Zweifel liegen an diesem Punkt. Bei ein paar Beispielen, die ich gesehen habe, wie man eine async Methode erstellt, die void zurückgibt, wird auf diese Weise, Task.Run oder TaskEx.Run, zurückgegriffen.

Wenn ich mich nicht irre, erstellt Task.Run einen neuen Thread, in dem die Methode ausgeführt wird. Warum also eine async Methode verwenden, wenn ich mit der Task, die einen neuen Thread erstellt, erreiche, was ich will, nämlich den Hauptthread nicht zu blockieren?

Außerdem, wenn die async Methode auf eine gemeinsam genutzte Variable zugreift, muss ich auf die Parallelität achten, richtig? Also ich sehe den Vorteil der Verwendung von async Methoden nicht, zumindest in diesem Fall.

Tatsächlich verwende ich denselben Code ohne async und ohne await und das Ergebnis ist dasselbe, das Hauptprogramm wird nicht blockiert und alles funktioniert wie erwartet. Die Methode lautet wie folgt:

private void method01Async()
{
    TaskEx.Run(() =>
    {
        UpdateTxtLog("Betritt method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("Verlassen von method01Async: " + System.DateTime.Now);
    });
}

Meine Frage lautet, ist dies der richtige Weg, um async zu verwenden, wenn die Methode void zurückgibt?

4voto

svick Punkte 224493

Wenn ich mich nicht irre, erstellt Task.Run einen neuen Thread, in dem die Methode ausgeführt wird.

Nicht genau. Task.Run() führt den Code auf einem Thread aus, der sich vom UI-Thread unterscheidet (zumindest mit dem standardmäßigen TaskScheduler). Es erstellt jedoch in den meisten Fällen keinen neuen Thread, sondern verwendet einen vorhandenen Thread aus dem ThreadPool.

Warum also eine async-Methode verwenden, wenn ich mit dem Task, der einen neuen Thread erstellt, das bekomme, was ich will, nämlich den Hauptthread nicht zu blockieren?

Der Zweck von async im Kontext einer UI-Anwendung besteht darin, nach Abschluss eines asynchronen Vorgangs einfachen Code auf dem UI-Thread auszuführen.

Wenn Sie also Ihre method01Async "awaitable" gemacht haben, d.h. sie einen Task zurückgeben lassen:

private async Task method01Async()
{
    await Task.Run(/* was auch immer */);
}

Dann könnten Sie sie von der Methode btnAsync01_Click aus awaiten, wenn Sie sie als `async` deklariert haben:

private async void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("Klick auf die Schaltfläche: " + System.DateTime.Now);
    await method01Async();
    UpdateTxtLog("nach method01Async: " + System.DateTime.Now);
}

Auf diese Weise wird die letzte Zeile der Methode nur ausgeführt, nachdem der Task in method01Async ausgeführt wurde. Und sie wird auf dem UI-Thread ausgeführt.

In .Net 4.0 könnten Sie einen ähnlichen Effekt mit ContinueWith() und Dispatcher.Invoke() erzielen:

private void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("Klick auf die Schaltfläche: " + System.DateTime.Now);
    method01Async().ContinueWith(() =>
        Dispatcher.Invoke(
            new Action(() =>
                UpdateTxtLog("nach method01Async: " + System.DateTime.Now)));
}

Sie werden sicher zustimmen, dass dies viel unordentlicher und weniger lesbar ist.

Außerdem, wenn die async-Methode auf eine gemeinsame Variable zugreift, muss ich auf die Nebenläufigkeit achten, richtig?

Ja, das stimmt.

Tatsächlich verwende ich denselben Code ohne async und ohne await und das Ergebnis ist dasselbe, das Hauptprogramm blockiert nicht und alles funktioniert wie erwartet.

Das Ergebnis ist sicherlich nicht das, was ich dachte, dass Ihr Code tun sollte. Die letzte Zeile von btnAsync01_Click wird "nach method01Async" ausgeführt, wartet jedoch nicht darauf, dass der in dieser Methode gestartete Task beendet wird.


Übrigens ist es nicht notwendig, in Ihrer method01Async `async` zu verwenden. Das direkte Rückgeben des Task (oder auch nicht, wenn Sie es lieber void-returning behalten möchten) funktioniert genauso:

private Task method01Async()
{
    return Task.Run(/* was auch immer */);
}

1voto

Chris Benard Punkte 3068

Sie nutzen das async in beiden Fällen nicht wirklich, da Sie den ursprünglichen Aufruf nicht abwarten. So sollten Sie es machen:

private async void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("Klicken Sie auf die Schaltfläche: " + System.DateTime.Now);
    await method01Async();
    UpdateTxtLog("nach ethod01Async: " + System.DateTime.Now);
}

private async Task method01Async()
{
    return await TaskEx.Run(() =>
    {
        UpdateTxtLog("Betreten Sie method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("Verlassen Sie method01Async: " + System.DateTime.Now);
    });
}

Wenn Sie dies ändern (der wichtige Teil ist await method01Async() in Ihrem Klickereignis für die Schaltfläche, wird es dorthin zurückkehren, nachdem es verlassen wurde, und Ihr Textprotokoll "nach ethod01Async: " sollte eine Verzögerung von zehn Sekunden anzeigen, ebenso wie Ihr Protokoll "Verlassen Sie method01Async" in der method01Async Methode.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X