private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
}
Éditer
En raison de la demande générale, je dois noter que le Task
lancement fonctionnera en parallèle avec le thread appelant. En supposant que la valeur par défaut, TaskScheduler
cela utilisera le .NET ThreadPool
. Quoi qu'il en soit, cela signifie que vous devez tenir compte du ou des paramètres passés au Task
comme étant potentiellement accessibles par plusieurs threads à la fois, ce qui en fait un état partagé. Cela inclut leur accès sur le fil appelant.
Dans mon code ci-dessus, ce cas est entièrement théorique. Les chaînes sont immuables. C'est pourquoi je les ai utilisés comme exemple. Mais disons que vous n'utilisez pas de String
...
Une solution consiste à utiliser async
et await
. Ceci, par défaut, capturera le SynchronizationContext
thread appelant et créera une continuation pour le reste de la méthode après l'appel à await
et l'attachera au fichier Task
. Si cette méthode s'exécute sur le thread d'interface graphique WinForms, elle sera de type WindowsFormsSynchronizationContext
.
La continuation s'exécutera après avoir été publiée sur le capturé SynchronizationContext
- encore une fois par défaut. Vous serez donc de retour sur le fil de discussion avec lequel vous avez commencé après l' await
appel. Vous pouvez modifier cela de différentes manières, notamment en utilisant ConfigureAwait
. En bref, le reste de cette méthode ne se poursuivra pas tant que le ne sera pas Task
terminé sur un autre thread. Mais le thread appelant continuera à s'exécuter en parallèle, mais pas le reste de la méthode.
Cette attente pour terminer l'exécution du reste de la méthode peut être souhaitable ou non. Si rien dans cette méthode n'accède plus tard aux paramètres passés à, Task
vous ne voudrez peut-être pas du tout utiliser await
.
Ou peut-être que vous utiliserez ces paramètres beaucoup plus tard dans la méthode. Aucune raison de le faire await
immédiatement car vous pouvez continuer à travailler en toute sécurité. N'oubliez pas que vous pouvez stocker le Task
retourné dans une variable et await
dessus plus tard - même dans la même méthode. Par exemple, une fois que vous avez besoin d'accéder aux paramètres passés en toute sécurité après avoir effectué un tas d'autres travaux. Encore une fois, vous n'avez pas besoin de await
le faire sur la Task
droite lorsque vous l'exécutez.
Quoi qu'il en soit, un moyen simple de rendre ce thread-safe par rapport aux paramètres passés à Task.Run
est de le faire:
Vous devez d'abord décorer RunAsync
avec async
:
private async void RunAsync()
Note importante
De préférence, la méthode marquée ne doit pas retourner void, comme le mentionne la documentation liée. L'exception courante à cela concerne les gestionnaires d'événements tels que les clics sur les boutons, etc. Ils doivent revenir nuls. Sinon, j'essaie toujours de retourner un ou lors de l'utilisation . C'est une bonne pratique pour plusieurs raisons.async
Task
Task<TResult>
async
Vous pouvez maintenant await
exécuter la Task
méthode ci-dessous. Vous ne pouvez pas utiliser await
sans async
.
await Task.Run(() => MethodWithParameter(param));
Donc, en général, si vous faites await
la tâche, vous pouvez éviter de traiter les paramètres passés comme une ressource potentiellement partagée avec tous les pièges de la modification de quelque chose à partir de plusieurs threads à la fois. Méfiez-vous également des fermetures . Je ne les couvrirai pas en profondeur, mais l'article lié fait un excellent travail.
Note d'accompagnement
Un peu hors sujet, mais soyez prudent en utilisant n'importe quel type de "blocage" sur le thread de l'interface graphique WinForms car il est marqué par [STAThread]
. L'utilisation await
ne bloquera pas du tout, mais je la vois parfois utilisée en conjonction avec une sorte de blocage.
"Bloquer" est entre guillemets car vous ne pouvez techniquement pas bloquer le thread d'interface graphique WinForms . Oui, si vous utilisez lock
sur le fil GUI WinForms , il va encore pomper des messages, malgré vous pensant qu'il est « bloqué ». Ce n'est pas.
Cela peut provoquer des problèmes bizarres dans de très rares cas. L'une des raisons pour lesquelles vous ne voulez jamais utiliser de lock
peinture, par exemple. Mais c'est un cas marginal et complexe; cependant je l'ai vu causer des problèmes insensés. Je l'ai donc noté par souci d'exhaustivité.