En C # 4.0, nous avons Task
dans l'espace de noms System.Threading.Tasks. Quelle est la vraie différence entre Thread
et Task
. J'ai fait quelques exemples de programme (aide pris de MSDN) pour mon propre apprentissage avec
Parallel.Invoke
Parallel.For
Parallel.ForEach
mais ayez beaucoup de doutes car l’idée n’est pas aussi claire.
Dans un premier temps, j'ai cherché dans Stackoverflow un type de question similaire, mais le titre de la question ne correspond peut-être pas au même résultat. Si quelqu'un sait que le même type de question a été posté ici plus tôt, veuillez indiquer la référence du lien.
Une tâche est quelque chose que vous voulez faire.
Un fil est l'un des nombreux ouvriers possibles qui effectuent cette tâche.
En termes .NET 4.0, Task représente une opération asynchrone. Les threads sont utilisés pour terminer cette opération en scindant le travail en morceaux et en affectant des threads séparés.
En termes d’informatique, un Task
est un futur ou une promesse . (Certaines personnes utilisent ces deux termes de façon synomyme, d'autres les utilisent différemment, personne ne peut s'accorder sur une définition précise .) Fondamentalement, un Task<T>
" promet "de te rendre un T
, mais pas maintenant chérie, je suis un peu occupé, pourquoi ne reviendrais-tu pas plus tard?
Un Thread
est un moyen de remplir cette promesse. Mais chaque Task
n'a pas besoin d'un tout nouveau Thread
. (En fait, créer un thread est souvent indésirable, car cela coûte beaucoup plus cher que de réutiliser un thread existant du pool de threads. Plus d'informations à ce sujet dans un instant.) Si la valeur que vous attendez provient du système de fichiers ou d'un fichier. base de données ou le réseau, il n’est pas nécessaire pour un thread de s’asseoir et d’attendre les données lorsqu’il peut traiter d’autres requêtes. Au lieu de cela, le Task
peut enregistrer un rappel pour recevoir la ou les valeurs lorsqu'il est prêt.
En particulier, le Task
ne fait pas pourquoi il est qu'il faut beaucoup de temps pour renvoyer la valeur. Il se peut que le calcul prenne beaucoup de temps ou que l'extraction prenne beaucoup de temps. Dans le premier cas, vous utiliseriez un Thread
pour exécuter un Task
. (Dans .NET, les threads coûtent très cher, vous devez donc généralement les éviter autant que possible et ne les utiliser que si vous souhaitez exécuter plusieurs calculs lourds sur plusieurs processeurs. Par exemple, sous Windows, un thread pèse 12 ki ( Je pense), sous Linux, un fil ne pèse que 4 Ko, en Erlang/BEAM, même 400 octets. En .NET, 1 MiByte!)
La solution simple, vous n'avez probablement pas besoin de l'utiliser, vous pouvez probablement utiliser une tâche LongRunning
et profiter des avantages de la bibliothèque TPL - Task Parallel Library, incluse dans .NET Framework 4 (février 2002) et ci-dessus (également .NET Core).
Abstraction au-dessus des fils. Il tilise le pool de threads (sauf si vous spécifiez la tâche comme une opération LongRunning
, si tel est le cas, un nouveau thread est créé sous le capot pour vous).
Comme son nom l'indique: un pool de threads. Le framework .NET gère-t-il un nombre limité de threads? Pourquoi? Car ouvrir 100 threads pour exécuter des opérations de processeur coûteuses sur un processeur avec seulement 8 cœurs n'est certainement pas une bonne idée. La structure maintiendra ce pool pour vous, en réutilisant les threads (sans les créer/les tuer à chaque opération) et en les exécutant en parallèle, de manière à ce que votre processeur ne brûle pas.
En résumé: utilisez toujours des tâches.
La tâche est une abstraction, elle est donc beaucoup plus facile à utiliser. Je vous conseille de toujours essayer d'utiliser des tâches et si vous rencontrez un problème qui vous oblige à gérer un fil par vous-même (probablement 1% du temps), utilisez-le.
LongRunning
tâches ( ou des discussions si vous avez besoin de ). Parce que l'utilisation de tâches vous mènerait à un pool de threads avec quelques threads occupés et de nombreuses autres tâches attendant son tour pour prendre le pool.Vous pouvez utiliser Task
pour spécifier ce que vous voulez faire, puis associez ce Task
à un Thread
. de sorte que Task
soit exécuté dans le Thread
nouvellement créé plutôt que sur le fil de l'interface graphique.
Utilisez Task
avec la TaskFactory.StartNew(Action action)
. Ici, vous exécutez un délégué, donc si vous n'utilisiez aucun thread, il serait exécuté dans le même thread (thread d'interface graphique). Si vous mentionnez un fil, vous pouvez exécuter cette Task
dans un autre fil. C'est un travail inutile car vous pouvez directement exécuter le délégué ou attacher ce délégué à un thread et exécuter ce délégué dans ce thread. Alors ne l'utilisez pas. c'est juste inutile. Si vous avez l’intention d’optimiser votre logiciel, c’est un bon candidat à supprimer.
** Veuillez noter que la Action
est une delegate
.
En plus des points ci-dessus, il serait bon de savoir que:
J'utilise habituellement Task
pour interagir avec Winforms et un simple arrière-plan pour éviter que l'interface utilisateur ne soit figée. voici un exemple où je préfère utiliser Task
private async void buttonDownload_Click(object sender, EventArgs e)
{
buttonDownload.Enabled = false;
await Task.Run(() => {
using (var client = new WebClient())
{
client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
}
})
buttonDownload.Enabled = true;
}
CONTRE
private void buttonDownload_Click(object sender, EventArgs e)
{
buttonDownload.Enabled = false;
Thread t = new Thread(() =>
{
using (var client = new WebClient())
{
client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
}
this.Invoke((MethodInvoker)delegate()
{
buttonDownload.Enabled = true;
});
});
t.IsBackground = true;
t.Start();
}
la différence est que vous n'avez pas besoin d'utiliser MethodInvoker
et un code plus court.