Comment utiliser le multi-threading avec des tâches en C#

Utilisation de la bibliothèque parallèle de tâches dans .NET 4.0

Vue latérale du programmeur à la recherche de code binaire au bureau

Przemyslaw Klos / EyeEm / Getty Images





La programmation informatique le terme 'thread' est l'abréviation de thread d'exécution, dans lequel un processeur suit un chemin spécifié à travers votre code. Le concept de suivre plus d'un thread à la fois introduit le sujet du multitâche et du multithreading.

Une application contient un ou plusieurs processus. Considérez un processus comme un programme exécuté sur votre ordinateur. Maintenant, chaque processus a un ou plusieurs threads. Une application de jeu peut avoir un thread pour charger des ressources à partir du disque, un autre pour faire de l'IA et un autre pour exécuter le jeu en tant que serveur.



Dans .NET/Windows, le système d'exploitation alloue du temps processeur à un thread. Chaque thread garde une trace des gestionnaires d'exceptions et de la priorité à laquelle il s'exécute, et il dispose d'un emplacement pour enregistrer le contexte du thread jusqu'à son exécution. Le contexte du thread est l'information dont le thread a besoin pour reprendre.

Multitâche avec threads

Les threads prennent un peu de mémoire et leur création prend un peu de temps, donc généralement, vous ne voulez pas en utiliser beaucoup. N'oubliez pas qu'ils se disputent le temps processeur. Si votre ordinateur dispose de plusieurs processeurs, Windows ou .NET peuvent exécuter chaque thread sur un processeur différent, mais si plusieurs threads s'exécutent sur le même processeur, un seul peut être actif à la fois et le changement de thread prend du temps.



Le CPU exécute un thread pendant quelques millions d'instructions, puis il passe à un autre thread. Tous les registres du processeur, le point d'exécution du programme en cours et la pile doivent être sauvegardés quelque part pour le premier thread, puis restaurés à partir d'un autre emplacement pour le thread suivant.

Création d'un fil

Dans l'espace de noms System. Enfilage , vous trouverez le type de fil. Le thread constructeur (ThreadStart) crée une instance d'un thread. Cependant, ces derniers temps C# code, il est plus probable de transmettre une expression lambda qui appelle la méthode avec n'importe quel paramètre.

Si vous n'êtes pas sûr de expressions lambda , cela vaut peut-être la peine de vérifier LINQ.

Voici un exemple de thread créé et démarré :



|__+_| |__+_|

Tout ce que fait cet exemple est d'écrire '1' sur la console. Le thread principal écrit un '0' sur la console 10 fois, à chaque fois suivi d'un 'A' ou d'un 'D' selon que l'autre thread est encore Alive ou Dead.

L'autre thread ne s'exécute qu'une seule fois et écrit un « 1 ». Après le délai d'une demi-seconde dans le thread Write1(), le thread se termine et le Task.IsAlive dans la boucle principale renvoie maintenant 'D.'



Pool de threads et bibliothèque parallèle de tâches

Au lieu de créer votre propre thread, à moins que vous n'en ayez vraiment besoin, utilisez un pool de threads. À partir de .NET 4.0, nous avons accès à la bibliothèque parallèle de tâches (TPL). Comme dans l'exemple précédent, encore une fois, nous avons besoin d'un peu de LINQ, et oui, ce sont toutes des expressions lambda.

Les tâches utilisent lePool de filsdans les coulisses mais mieux utiliser les fils en fonction du nombre utilisé.



L'objet principal dans le TPL est une tâche. Il s'agit d'une classe qui représente une opération asynchrone. La façon la plus courante de démarrer les choses est avec le Task.Factory.StartNew comme dans :

|__+_|

Où DoSomething() est la méthode exécutée. Il est possible de créer une tâche et de ne pas l'exécuter immédiatement. Dans ce cas, utilisez simplement Task comme ceci :



|__+_|

Cela ne démarre pas le thread tant que le .Start() n'est pas appelé. Dans l'exemple ci-dessous, sont cinq tâches.

|__+_|

Exécutez cela et vous obtenez les chiffres 0 à 4 dans un ordre aléatoire tel que 03214. C'est parce que l'ordre d'exécution des tâches est déterminé par .NET.

Vous vous demandez peut-être pourquoi la valeur var = i est nécessaire. Essayez de le supprimer et d'appeler Write(i), et vous verrez quelque chose d'inattendu comme 55555. Pourquoi cela ? C'est parce que la tâche affiche la valeur de i au moment où la tâche est exécutée, pas au moment où la tâche a été créée. En créant un nouveau variable à chaque fois dans la boucle, chacune des cinq valeurs est correctement stockée et récupérée.