Est-il possible de changer parallelOptions.MaxDegreeOfParallelism pendant l’exécution d’un Parallel.ForEach

Je lance une boucle multi-threadée:

protected ParallelOptions parallelOptions = new ParallelOptions(); parallelOptions.MaxDegreeOfParallelism = 2; Parallel.ForEach(items, parallelOptions, item => { // Loop code here }); 

Je veux changer le parallelOptions.MaxDegreeOfParallelism pendant l’exécution de la boucle parallèle pour réduire ou augmenter un nombre de threads.

 parallelOptions.MaxDegreeOfParallelism = 5; 

Il ne semble pas augmenter les fils. Quelqu’un a-t-il une idée?

Le problème, même en essayant de faire cela, c’est que c’est un problème difficile. Pour commencer, comment observez-vous l’utilisation du processeur et du disque de manière fiable? L’échantillonnage peu fréquent de la CPU donnera une image médiocre de ce qui se passe réellement et l’utilisation de l’échantillonnage de disque est encore plus difficile. Deuxièmement, quelle est la granularité de vos tâches et à quelle fréquence pouvez-vous rapidement changer le nombre de tâches en cours d’exécution. Troisièmement, les choses changent rapidement avec le temps, vous devez donc appliquer une sorte de filtrage à vos observations. Quasortingèmement, le nombre idéal de threads dépend du processeur sur lequel le code est exécuté. Cinquièmement, si vous allouez trop de threads, vous vous en disputerez au lieu de faire un travail utile.

Voir http://msdn.microsoft.com/en-us/magazine/ff960958.aspx pour une discussion sur la façon dont le pool de threads dans .NET gère la tâche complexe consistant à décider du nombre de threads à utiliser.

Vous pouvez également utiliser réflecteur et jeter un coup d’œil au code utilisé par TPL pour allouer des threads et éviter les changements de contexte inutiles – c’est complexe et cela ne prend même pas en compte l’access au disque!

Vous pouvez plutôt essayer d’exécuter les tâches sur un thread de priorité inférieure (créer votre propre TaskScheduler qui exécute des threads avec une priorité inférieure à la normale est en fait assez facile). Cela garantira au moins que vous pouvez utiliser 100% de votre CPU sans impacter le rest du système. S’amuser avec les priorités de threads est en soi semé d’embûches, mais s’il s’agit d’une tâche purement en tâche de fond, cela peut être simple et peut aider.

Bien souvent, l’utilisation du disque est le véritable coupable des autres applications victimes d’une application gourmande. Windows peut facilement allouer le processeur de manière équitable entre les applications, mais lorsque l’access au disque est relativement lent, c’est tout autre chose. Au lieu d’essayer d’ajuster dynamicment le nombre de threads en cours d’exécution, vous devrez peut-être simplement limiter votre application de sorte qu’elle n’accède pas trop souvent au disque. C’est quelque chose que vous pouvez faire sans changer le nombre de threads actifs.

Vous pouvez également SetPriorityClass pour informer le système d’exploitation que votre processus est moins important que d’autres applications s’exécutant sur le système. Voir Comment augmenter la priorité d’E / S d’un processus? pour plus d’informations. Mais cela suppose que tout votre processus est moins important, pas seulement cette partie-là.

Je ne m’attendrais pas à ce qu’il soit possible de modifier le degré de parallélisme après avoir appelé ForEach . Si j’ai bien compris, ForEach va déterminer le nombre de threads qu’il peut créer, créer autant de partitions et créer les threads à utiliser sur ces partitions. À aucun moment, il ne peut dire: “Oh, attendez, il a changé notre allocation de ressources, laissez-moi re-partitionner le tableau et ré-allouer les threads.”