private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
}
Bearbeiten
Aufgrund der großen Nachfrage muss ich beachten, dass der Task
Start parallel zum aufrufenden Thread ausgeführt wird. Unter der Annahme der Standardeinstellung TaskScheduler
wird .NET verwendet ThreadPool
. Auf jeden Fall bedeutet dies, dass Sie berücksichtigen müssen, welche Parameter an die Task
potenziell als von mehreren Threads gleichzeitig zugegriffen werden, sodass sie gemeinsam genutzt werden. Dies beinhaltet den Zugriff auf sie im aufrufenden Thread.
In meinem obigen Code ist dieser Fall völlig umstritten. Saiten sind unveränderlich. Deshalb habe ich sie als Beispiel genommen. Aber sagen Sie, Sie verwenden keine String
...
Eine Lösung ist die Verwendung von async
und await
. Dies erfasst standardmäßig SynchronizationContext
den aufrufenden Thread und erstellt nach dem Aufruf eine Fortsetzung für den Rest der Methode await
und hängt sie an den erstellten an Task
. Wenn diese Methode auf dem WinForms-GUI-Thread ausgeführt wird, ist sie vom Typ WindowsFormsSynchronizationContext
.
Die Fortsetzung wird ausgeführt, nachdem sie wieder in den erfassten Bereich gebucht wurde SynchronizationContext
- wiederum nur standardmäßig. Sie befinden sich also wieder in dem Thread, mit dem Sie nach dem await
Aufruf begonnen haben. Sie können dies auf verschiedene Arten ändern, insbesondere mit ConfigureAwait
. Kurz gesagt, der Rest dieser Methode wird erst fortgesetzt, nachdem der Task
Vorgang in einem anderen Thread abgeschlossen wurde. Der aufrufende Thread wird jedoch weiterhin parallel ausgeführt, nur nicht der Rest der Methode.
Dieses Warten auf den Abschluss des Restes der Methode kann wünschenswert sein oder auch nicht. Wenn nichts in dieser Methode später auf die Parameter zugreift, die an übergeben wurden, Task
möchten Sie sie möglicherweise überhaupt nicht verwenden await
.
Oder vielleicht verwenden Sie diese Parameter viel später in der Methode. Kein Grund, await
sofort, da Sie sicher weiterarbeiten können. Denken Sie daran, dass Sie die zurückgegebenen Task
Daten in einer Variablen und await
später darauf speichern können - auch mit derselben Methode. Zum Beispiel, wenn Sie nach einer Reihe anderer Arbeiten sicher auf die übergebenen Parameter zugreifen müssen. Auch hier haben Sie nicht brauchen , um await
auf dem Task
Recht , wenn Sie es starten.
Eine einfache Möglichkeit, diesen Thread in Bezug auf die übergebenen Parameter sicher zu machen, Task.Run
besteht darin, Folgendes zu tun:
Sie müssen zuerst dekorieren RunAsync
mit async
:
private async void RunAsync()
Wichtige Notiz
Vorzugsweise sollte die markierte Methode nicht ungültig sein, wie in der verknüpften Dokumentation erwähnt. Die häufigste Ausnahme sind Ereignishandler wie Schaltflächenklicks und dergleichen. Sie müssen ungültig zurückkehren. Ansonsten versuche ich immer ein oder bei Verwendung zurückzugeben . Es ist aus mehreren Gründen eine gute Übung.async
Task
Task<TResult>
async
Jetzt können Sie await
das Task
Folgende unten ausführen. Sie können nicht await
ohne verwenden async
.
await Task.Run(() => MethodWithParameter(param));
Wenn Sie also await
die Aufgabe übernehmen, können Sie im Allgemeinen vermeiden, übergebene Parameter als potenziell gemeinsam genutzte Ressource zu behandeln, mit all den Gefahren, etwas aus mehreren Threads gleichzeitig zu ändern. Achten Sie auch auf Verschlüsse . Ich werde nicht näher darauf eingehen, aber der verlinkte Artikel leistet hervorragende Arbeit.
Randnotiz
Ein bisschen abseits des Themas, aber seien Sie vorsichtig, wenn Sie den WinForms-GUI-Thread mit "Blockieren" versehen, da er mit markiert ist [STAThread]
. Die Verwendung await
wird überhaupt nicht blockiert, aber ich sehe manchmal, dass sie in Verbindung mit einer Art Blockierung verwendet wird.
"Blockieren" steht in Anführungszeichen, da Sie den WinForms-GUI-Thread technisch nicht blockieren können . Ja, wenn Sie lock
den WinForms-GUI-Thread verwenden, werden weiterhin Nachrichten gepumpt, obwohl Sie denken, dass er "blockiert" ist. Es ist nicht.
Dies kann in sehr seltenen Fällen bizarre Probleme verursachen. Einer der Gründe, warum Sie lock
zum Beispiel beim Malen niemals einen verwenden möchten . Aber das ist ein Randfall und ein komplexer Fall. Ich habe jedoch gesehen, dass es verrückte Probleme verursacht. Der Vollständigkeit halber habe ich es notiert.