Parallel.ForEach Block?

时间:2012-04-14 12:44:35

标签: c# .net multithreading logging parallel-processing

.net函数Parallel.ForEach是否会阻塞调用线程?我对行为的猜测是其中之一:

  1. 是的,它会阻止,直到最慢的项目执行返回。
  2. 不,它不会阻止并立即返回控制。并行运行的项目在后台线程上完成。
  3. 或许其他事情正在发生,有人确切知道吗?

    在日志记录类中实现此问题时出现了这个问题:

    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};
        }
    }
    

    请注意LogMessage方法调用其他一些日志记录服务。我需要该部分立即返回,因此它不会阻止调用线程。


    更新:基于其他人的评论(我们已确认行为为#1)。所以我已经建议使用Task库并重写这样的循环:

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

2 个答案:

答案 0 :(得分:55)

1号是正确的;在循环完成之前,Parallel.ForEach不会返回。如果您不想要这种行为,您只需将您的循环执行为Task并在另一个线程上运行它。

答案 1 :(得分:10)

在正常的foreach()中重新启动你的更新,StartNew:

对于大型集合而言,这可能不是最佳选择,并且您无法处理错误。

您的loggingServices可能不包含数千个项目,但错误处理仍然是一个问题。

考虑:

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