Quand utiliser TaskCreationOptions.LongRunning?
je me le demande depuis longtemps, mais je n'ai jamais vraiment trouvé la réponse.
je comprends que c'est un indice pour le planificateur de tâches où la tâche sera exécutée, et que le planificateur de tâches (ou de nos jours?) décider d'instancier un non-thread du pool de thread pour cette tâche.
ce que je ne sais pas (et étonnamment Je ne trouve nulle part sur internet) est une "règle empirique" quand spécifier une tâche comme étant de longue durée. Est d'une seconde de temps? 30 secondes? Une minute? Cinq minutes? A-t-elle un rapport avec la quantité de tâches, l'application utilise? Dois-je, en tant que programmeur, faire des calculs avec les #threads dans le pool de threads, combien de tâches je crée, combien seront longues à exécuter en même temps, et sur la base de cela prendre une décision d'utiliser ou non une tâche longue à exécuter?
j'Espère apprendre quelque chose ici.
4 réponses
il peut être quantifié, le gestionnaire threadpool ajoute un extra thread au-delà de l'optimum lorsque les threads tp existants ne sont pas terminés assez tôt. Il le fait deux fois par seconde, jusqu'au maximum défini par SetMaxThreads(). Qui a un très la valeur par défaut. L'optimum est le nombre de cœurs de processeur de la machine disponible, 4 est typique. Exécuter plus de threads que les noyaux disponibles peut être préjudiciable en raison de la commutation de contexte généraux.
Il ne en se fondant sur les hypothèse que ces threads existants ne progressent pas parce qu'ils n'exécutent pas assez de code. En d'autres termes, ils bloquent sur l'entrée/sortie ou une serrure trop. De tels threads n'utilisent donc pas les noyaux assez efficacement et permettre l'exécution d'un thread supplémentaire est tout à fait approprié pour augmenter l'utilisation du processeur et obtenir plus de travail fait.
Donc, c'est "long cours" si le thread prend plus d'une demi-seconde. Gardez à l'esprit que c'est un temps très long, il équivaut à environ 4 milliards d'instructions de processeur sur une machine de classe de bureau moderne. A moins que vous n'utilisiez un code de calcul lourd comme calculer la valeur de pi à un million de chiffres, donc exécuter ces 4 milliards d'instructions, un thread pratique ne peut prendre que ce temps quand il bloc trop souvent. Ce qui est très courant, quelque chose comme une requête dbase est souvent lente et exécutée sur un thread de worker et consomme peu CPU.
il vous appartient par ailleurs de vérifier que l'hypothèse que le gestionnaire de threadpool fera est exacte. La tâche devrait prendre beaucoup de temps car le processeur n'est pas utilisé efficacement. Le gestionnaire de tâches est un moyen simple de voir ce que les noyaux du processeur font dans votre programme, bien qu'il ne vous dise pas exactement quel code ils exécutent. Vous aurez besoin d'un test unitaire pour voir le thread exécuter en isolation. L'ultime et seule complètement précis vous dire que l'utilisation de LongRunning était un choix approprié est de vérifier que votre application obtient en effet plus de travail.
modifier la réponse de Hans avec laquelle je suis en grande partie d'accord.
la raison La plus importante pour spécifier LongRunning
est d'obtenir une exécution pratiquement garantie et quasi immédiate. Il n'y aura pas d'attente pour le pool de threads pour émettre un thread à votre article de travail. Je dis "pratiquement" parce que L'OS est libre de ne pas programmer votre fil. Mais vous aurez une part du CPU et ça ne prendra pas longtemps avant que ça arrive.
Vous êtes de sauter dans l'avant de la file d'attente en spécifiant LongRunning
. Pas besoin d'attendre que le pool de threads émette 2 threads par seconde s'il est sous charge.
donc vous utiliserez LongRunning
pour des choses qui ne doivent pas nécessairement se produire de la façon la plus efficace, mais de façon opportune et régulière. Par exemple, certains travaux D'UI, la boucle de jeu, le rapport d'avancement,...
Démarrer et arrêter un thread coûte de l'ordre de 1ms de temps CPU. Il s'agit de beaucoup plus que l'émission de thread pool de travaux. Je viens de il s'agit de 3M articles publiés et achevés par seconde. Le benchmark était tout à fait artificiel, mais l'ordre de grandeur est juste.
LongRunning
est documenté pour être un indice, mais il est absolument efficace dans la pratique. Il n'y a pas d'heuristique qui tienne compte de votre allusion. C'est supposé être correct.
quand spécifier une tâche longue
cela dépend de la tâche à accomplir. Si la tâche contient des while(true) {...}
et vit jusqu'à l'arrêt de l'application, puis il un sens à préciser LongRunning
. Si vous créez une tâche file une certaine opération et empêcher le blocage du thread courant alors vous ne vous en souciez pas vraiment (ne pas spécifier quoi que ce soit).
cela dépend de ce que font les autres tâches. Peu importe si vous exécutez quelques tâches avec ou sans LongRunning
. Mais il pourrait être un problème de créer des milliers de tâches, où chaque demande nouveau fil. Ou à l'opposé, vous pouvez rencontrer threads sans l'indiquer.
une façon facile d'y penser est celle-ci: préférez-vous une nouvelle tâche à exécuter dans un nouveau thread ou vous vous en fichez? Si d'abord - ensuite, utilisez LongRunningOption
. Ce ne signifie pas quelle tâche va s'exécuter dans un autre thread, c'est juste un bon critère quand vous devez le spécifier.
E. g. lorsque en utilisant ContinueWith
LongRunning
est à l'opposé de ExecuteSynchronously
(il y a un case pour éviter que les deux ne soient spécifiés). Si vous avez des continuations multiples, alors peut - être que vous voulez éviter au-dessus de la file d'attente et exécuter la suite spécifique dans le même thread ou en face-vous ne voulez pas que l'une des continuations interfère avec les autres et alors vous pouvez utiliser spécifiquement LongRunning
. Reportez-vous à cet article (et )ExecuteSynchronously
.
une tâche de longue durée est une tâche qui peut entrer dans un État d'attente, bloquant le thread sur lequel elle s'exécute, ou une tâche qui prend trop de temps CPU (nous reviendrons sur celle-ci).
certains peuvent dire que cette définition est trop large, beaucoup de tâches seraient de longue durée, mais pensez-y, même si l'attente est limitée à un petit délai, la tâche n'est toujours pas l'utilisation efficace du CPU. Si le nombre de ces tâches augmente, vous constaterez qu'elles ne dépassent pas linéairement les charges de travail des mineurs (voir ThreadPool.SetMinThreads
), la dégradation est vraiment mauvais.
l'approche il pour basculer tous les e/s (Fichier, réseau, DB, etc.) asynchrone.
il y a aussi des tâches de longue durée en raison de longs calculs intensifs en CPU.
l'approche consiste à reporter le calcul, par exemple en insérant await Task.Yield()
à certains moments, ou de préférence en différant explicitement le calcul en programmant une tâche après l'autre, chaque traitement d'un morceau de données déjà divisé ou un processus a en mémoire tampon jusqu'à un délimitée limite de temps.
Le "trop de temps" est à vous de décider.
lorsque vous êtes dans un environnement où vous partagez le thread pool, chaque fois que le temps est trop long, vous devez choisir une valeur raisonnable.
plus généralement, "trop de temps" est quand les éléments de travail sont mis en file d'attente plus rapidement qu'ils ne sont traités. Il peut y avoir des rafales de travail, donc vous devriez faire la moyenne sur l'Unité de temps qui vous importe, que ce soit une seconde, une minute, 10 minutes, etc. Quand vous avez un SLA, vous devriez avoir cet intervalle défini quelque part.
après avoir une valeur sensible, vous devez voir, dans la pratique, s'il est correct de l'augmenter ou si vous devez la diminuer. Le plus souvent, si vous pouvez l'augmenter, vous êtes mieux l'augmenter, sauf si vous pouvez voir une différence de performance significative. "Significatif" signifie que le nombre d'articles traités augmente de façon plus que linéaire, donc si c'est linéaire (ou en dessous de linéaire, cela peut arriver), ne le faites pas.
d'après mon expérience, si vous avez une tâche de longue durée selon l'une de ces définitions, Vous êtes généralement mieux avec la gestion de votre propre thread ou ensemble de threads.