Est-ce que Parallel.ForEach Block?

La fonction .net Parallel.ForEach bloque-t-elle le thread appelant? Ma conjecture quant au comportement est l’un de ceux-ci:

  1. Oui, il bloque jusqu’à ce que l’élément le plus lent exécute le retour.
  2. Non, cela ne bloque pas et renvoie le contrôle immédiatement. Les éléments à exécuter en parallèle sont exécutés sur des threads d’arrière-plan.

Ou peut-être quelque chose d’autre se passe-t-il?

Cette question a été soulevée lors de l’implémentation dans une classe de journalisation:

public class MultipleLoggingService : LoggingServiceBase { private readonly List loggingServices; public MultipleLoggingService(List loggingServices) { this.loggingServices = loggingServices; LogLevelChanged += OnLogLevelChanged; } private void OnLogLevelChanged(object sender, LogLevelChangedArgs args) { loggingServices.ForEach(l => l.LogLevel = LogLevel); } public override LogMessageResponse LogMessage(LogMessageRequest request) { if (request.LogMessage) Parallel.ForEach(loggingServices, l => l.LogMessage(request)); return new LogMessageResponse{MessageLogged = request.LogMessage}; } } 

Notez que la méthode LogMessage appelle d’autres services de journalisation. J’ai besoin que cette partie revienne immédiatement, elle ne bloque donc pas le thread appelant.


Mise à jour: Basé sur les commentaires des autres (nous avons confirmé que le comportement est # 1). J’ai donc pris conseil d’utiliser la bibliothèque de tâches et de réécrire la boucle comme ceci:

  if (request.LogMessage) foreach (var loggingService in loggingServices) Task.Factory.StartNew(() => loggingService.LogMessage(request)); 

Le numéro 1 est correct Parallel.ForEach ne revient pas tant que la boucle n’est pas terminée. Si vous ne voulez pas ce comportement, vous pouvez simplement exécuter votre boucle en tant que Task et l’exécuter sur un autre thread.

Re votre mise à jour, StartNew dans un foreach normal ():

Ce n’est peut-être pas la solution la plus optimale pour les grandes collections et vous ne recevez aucun point pour gérer les erreurs.

Votre loggingServices ne contient probablement pas des milliers d’éléments, mais la gestion des erreurs rest un point.

Considérer:

 Task.Factory.StartNew(() => { try { Parallel.ForEach(loggingServices, l => l.LogMessage(request)); } catch(SomeException ex) { // at least try to log it ... } });