La bibliothèque parallèle de tâches (ou PLINQ) prennent d'autres processus en compte?

StackOverflow https://stackoverflow.com/questions/3488381

  •  28-09-2019
  •  | 
  •  

Question

Je cherche à utiliser TPL pour commencer (et attendre) des processus externes, en particulier,. Est-ce que l'aspect TPL à la charge totale de la machine (les deux CPU et d'E / S) avant de décider de lancer une autre tâche (donc - dans mon cas - un autre processus externe)?

Par exemple:

J'ai obtenu environ 100 fichiers multimédias qui doivent être codées ou transcodé (par exemple de WAV en FLAC ou de FLAC en MP3). Le codage est effectué en lançant un processus externe (par exemple FLAC.EXE ou lame.exe). Chaque fichier prend environ 30 secondes. Chaque processus est principalement lié CPU, mais il y a une entrée / sortie là-dedans. J'ai 4 cœurs, donc le pire des cas (transcoder en canalisant le décodeur dans le codeur) utilise encore que 2 noyaux. Je voudrais faire quelque chose comme:

Parallel.ForEach(sourceFiles,
    sourceFile =>
        TranscodeUsingPipedExternalProcesses(sourceFile));

Est-ce que ce coup d'envoi 100 tâches (et donc 200 processus externes en compétition pour le CPU)? Ou bien voir que occupé et que faire 2-3 à un moment de la CPU?

Était-ce utile?

La solution

Vous allez courir dans quelques problèmes ici. Le mécanisme d'évitement de la famine du planificateur verra vos tâches bloquées dans l'attente sur les processus. Il sera difficile de faire la distinction entre un fil et une impasse simplement en attente d'un processus complet. Par conséquent, il peut planifier de nouvelles tâches si vos tâches sont exécutées ou depuis longtemps (voir ci-dessous). L'heuristique hillclimbing doit tenir compte de la charge globale du système, à la fois de votre application et d'autres. Il essaie simplement de maximiser le travail effectué, il ajoutera plus de travail jusqu'à ce que le débit global du système cesse d'augmenter et il reculera. Je ne suis pas pense ce sera l'effet de votre application, mais la question de l'évitement stavation sera probablement.

Vous pouvez trouver plus de détails sur la façon dont tout cela fonctionne dans Programmation parallèle avec Microsoft®.NET , Colin Campbell, Ralph Johnson, Ade Miller, Stephen Toub (une version antérieure est en ligne ) .

"Le pool de threads .NET gère automatiquement le nombre de travailleurs threads dans le pool. Il ajoute et enlève des fils selon intégré heuristiques. Le pool de threads .NET a deux principaux mécanismes d'injection fils: un mécanisme d'évitement de la famine qui ajoute travailleur fils si elle voit aucun progrès faits sur des articles en attente et un hillclimbing heuristique qui tente de maximiser le débit lors de l'utilisation en tant que quelques fils possible.

Le but d'éviter la famine est d'empêcher l'impasse. Cette sorte de blocage peut se produire quand un thread attend de travail pour une synchronisation événement qui ne peut être satisfaite par un élément de travail qui est toujours en attente dans les files d'attente globales ou locales de la piscine de fil. S'il y avait un fixe nombre de threads de travail, et tous ces fils étaient tout aussi bloqué, le système serait incapable de jamais faire de nouveaux progrès. Ajout d'un nouveau thread de travail résout le problème.

Un but de l'heuristique colline escalade est d'améliorer l'utilisation des noyaux lorsque les fils sont bloqués par les E / S ou d'autres conditions d'attente que le processeur de décrochage. Par défaut, le pool de threads géré a un thread de travail par noyau. Si l'un de ces threads de travail devient bloqué, il y a une chance qu'un noyau pourrait être sous-utilisé, selon la charge de travail globale de l'ordinateur. La logique d'injection de fil ne distingue pas entre un fil qui est bloqué et un fil que ça l'exécution d'une opération longue, processeur. Par conséquent, chaque fois que les files d'attente globales ou locales du pool de threads contiennent en attente éléments de travail, les éléments de travail actifs qui prennent beaucoup de temps pour courir (plus de une demi-seconde) peut déclencher la création d'un nouveau pool worker de fil threads.

Le pool de threads .NET a la possibilité d'injecter toutes les discussions chronométrer un finalise d'élément de travail ou à 500 milliseconde intervalles, selon est plus courte. Le pool de threads utilise cette occasion pour essayer d'ajouter des fils (Ou les éloignant), guidé par les commentaires des changements précédents en le nombre de threads. Si l'ajout de fils semble aider le débit, le pool de threads ajoute plus; sinon, il réduit le nombre de threads de travail. Cette technique est appelée l'heuristique de montagne d'escalade. Par conséquent, l'une des raisons de garder les tâches individuelles courte est d'éviter « La détection de la famine », mais une autre raison de les garder court est de donner le pool de threads plus de possibilités pour améliorer le débit par ajuster le nombre de threads. Plus la durée de l'individu tâches, le pool de threads plus souvent peut mesurer le débit et ajuster le nombre de threads en conséquence.

Pour faire ce béton, prenons un exemple extrême de. Supposer que vous avez une simulation financière complexe avec 500 processeurs à forte intensité opérations, dont chacun prend dix minutes en moyenne compléter. Si vous créez des tâches de niveau supérieur dans la file d'attente globale pour chaque de ces opérations, vous constaterez que after environ cinq minutes la pool de threads passera à 500 threads de travail. La raison en est que la pool de threads voit toutes les tâches que bloqué et commence à ajouter de nouvelles fils à raison d'environ deux fils par seconde.

Le mal de Qu'est-ce avec 500 threads de travail? En principe, rien, si vous avez 500 cœurs pour eux d'utiliser et de grandes quantités de système Mémoire. En fait, c'est la vision à long terme du calcul parallèle. Toutefois, si vous ne disposez pas que beaucoup de cœurs sur votre ordinateur, vous êtes dans une situation où beaucoup de discussions sont en concurrence pour les tranches de temps. Cette situation est connue comme processeur sursouscription. Permettre à de nombreux threads de processeur à forte intensité de concourir pour le temps sur un seul noyau ajoute surdébit de changement de contexte qui permet de réduire considérablement l'ensemble du système débit. Même si vous ne courez pas de mémoire, la performance dans ce situation peut être bien, bien pire que dans le calcul séquentiel. (Chaque changement de contexte prend entre 6000 et 8000 cycles de processeur). Le coût de changement de contexte n'est pas la seule source de frais généraux. Un fil géré .NET consomme environ un mégaoctet de pile l'espace, que ce soit ou non que l'espace est utilisé pour exécuter les fonctions actuellement. Il faut environ 200 000 cycles de CPU pour créer un nouveau thread, et environ 100 000 cycles à la retraite d'un fil. Ce sont des opérations coûteuses.

Tant que vos tâches ne pas chaque minutes de prendre, est la piscine de fil algorithme colline escalade finira par se rendre compte qu'il a trop de fils et le dos de coupe sur elle-même. Toutefois, si vous avez des tâches occuper un thread de travail pendant de nombreuses secondes ou minutes ou heures, que jetteront au large des heuristiques de la piscine de fil, et à ce moment vous devraient envisager une solution de rechange.

La première option consiste à décomposer votre application en court tâches assez vite complet pour le pool de threads à succès contrôler le nombre de fils pour un débit optimal. Une deuxième possibilité est d'implémenter votre propre planificateur de tâches objet qui ne réalise pas d'injection de fil. Si vos tâches sont de longue durée, vous n'avez pas besoin d'un planificateur de tâches hautement optimisé, car le coût de la planification sera négligeable par rapport à l'exécution le temps de la tâche. programme développeur MSDN® a un exemple de tâche simple mise en œuvre du planificateur qui limite le degré maximum de la concurrence. Pour plus d'informations, consultez la section « Autres lectures » à la fin de ce chapitre.

En dernier recours, vous pouvez utiliser la méthode SetMaxThreads à configurer la classe ThreadPool avec une limite supérieure pour le nombre de threads de travail, généralement égal au nombre de noyaux (ce qui est le propriété Environment.ProcessorCount). Cette limite supérieure applique pour l'ensemble du processus, y compris tous les domaines d'application ».

Autres conseils

La réponse courte est:. Pas

interne, le TPL utilise la norme ThreadPool pour planifier ses tâches. Donc, vous vous demandez si le fait ThreadPool prend la charge de la machine en compte et il ne fonctionne pas. La seule chose qui limite le nombre de tâches en cours d'exécution simultanément est le nombre de threads dans le pool de threads, rien d'autre.

Est-il possible d'avoir les processus externes font rapport à votre demande une fois qu'ils sont prêts? Dans ce cas, vous ne devez pas attendre pour eux (fils de maintien occupés).

a publié un test à l'aide TPL / ThreadPool pour planifier un grand nombre de tâches qui font des tours en boucle. En utilisant une application externe j'ai chargé l'un des noyaux à 100% en utilisant une affinité de proc. Le nombre de tâches ne diminue.

Mieux encore, j'ai couru plusieurs instances de la même UC .NET TPL activé app. Le nombre de threads pour toutes les applications était le même, et n'a jamais été inférieur au nombre de cœurs, même si ma machine était à peine utilisable.

théorie donc de côté, TPL utilise le nombre de cœurs disponibles, mais jamais sur leur contrôle charge réelle. Une mise en œuvre très pauvre à mon avis.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top