La fonction .net Parallel.ForEach bloque-t-elle le thread appelant? Ma conjecture quant au comportement est l'une d'entre elles:
Ou peut-être que quelque chose d'autre se passe, quelqu'un le sait avec certitude?
Cette question s'est posée lors de l'implémentation de ceci dans une classe de journalisation:
public class MultipleLoggingService : LoggingServiceBase
{
private readonly List<LoggingServiceBase> loggingServices;
public MultipleLoggingService(List<LoggingServiceBase> 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, donc elle ne bloque pas le thread appelant.
Mise à jour: Basé sur les commentaires des autres (nous avons confirmé que le comportement est n ° 1). J'ai donc pris conseil d'utiliser la bibliothèque Task et réécrit 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 que lorsque la boucle est terminée. Si vous ne souhaitez 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 le plus optimal pour les grandes collections, et vous n'obtenez aucun point pour gérer les erreurs.
Vos services de journalisation ne contiennent probablement pas des milliers d'éléments, mais la gestion des erreurs reste un point.
Considérer:
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(loggingServices, l => l.LogMessage(request));
}
catch(SomeException ex)
{
// at least try to log it ...
}
});