Multi-threading en C # avec des tâches

le programmation informatique 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 plusieurs threads à la fois introduit le sujet du multitâche et du multithread.

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 a un endroit pour enregistrer le contexte du thread jusqu'à ce qu'il s'exécute. Le contexte du thread est l'information que le thread doit reprendre.

Multi-tâches avec des 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, ils se disputent le temps processeur. Si votre ordinateur possède plusieurs processeurs, Windows ou .NET peut exécuter chaque thread sur un processeur différent, mais si plusieurs threads s'exécutent sur le même CPU, alors un seul peut être actif à la fois et le changement de thread prend temps.

instagram viewer

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

Créer un fil

Dans le système d'espace de noms. Enfiler, vous trouverez le type de fil. Le fil conducteur (ThreadStart) crée une instance d'un thread. Cependant, au cours des dernières C # code, il est plus probable de passer dans une expression lambda qui appelle la méthode avec tous les paramètres.

Si vous n'êtes pas sûr expressions lambda, il peut être utile de consulter LINQ.

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

en utilisant le système;
en utilisant le système. Threading;
espace de noms ex1
{
Programme de cours
{
public static void Write1 ()
{
Console. Écrire ('1');
Fil. Sommeil (500);
}
statique void Main (chaîne [] args)
{
var task = nouveau Thread (Write1);
tâche. Début() ;
pour (var i = 0; i <10; i ++)
{
Console. Write ('0');
Console. Écrire (tâche. Est vivant? 'UN D') ;
Fil. Sommeil (150);
}
Console. ReadKey ();
}
}
}

Tout cet exemple ne fait qu'écrire "1" sur la console. Le thread principal écrit un «0» sur la console 10 fois, suivi à chaque fois d'un «A» ou d'un «D» selon que l'autre thread est toujours vivant ou mort.

L'autre thread s'exécute 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 la tâche. IsAlive dans la boucle principale retourne désormais "D."

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

Au lieu de créer votre propre thread, sauf si vous en avez vraiment besoin, utilisez un Thread Pool. À 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.

Tâches utilise le Pool de threads dans les coulisses mais mieux utiliser les threads en fonction du nombre utilisé.

L'objet principal du 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 la tâche. Usine. Nouveau comme dans:

Tâche. Usine. StartNew (() => DoSomething ());

Où DoSomething () est la méthode qui est 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:

var t = new Task (() => Console. WriteLine ("Bonjour"));
...
t. Début();

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

en utilisant le système;
en utilisant le système. Threading;
en utilisant le système. Enfiler. Tâches;
espace de noms ex1
{
Programme de cours
{
public static void Write1 (int i)
{
Console. Écrivez (i);
Fil. Sommeil (50);
}
statique void Main (chaîne [] args)
{
pour (var i = 0; i <5; i ++)
{
valeur var = i;
var runningTask = Tâche. Usine. StartNew (() => Write1 (valeur));
}
Console. ReadKey ();
}
}
}

Exécutez cela et vous obtenez la sortie des chiffres de 0 à 4 dans un ordre aléatoire tel que 03214. En effet, 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 est-ce? C'est parce que la tâche affiche la valeur de i au moment où la tâche est exécutée, pas lorsque 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 captée.

instagram story viewer