Parallel.ForEach会阻塞吗?

56

.NET 函数 Parallel.ForEach 是否会阻塞调用线程?我猜测有以下两种行为:

  1. 是的,它会阻塞直到最慢执行项返回。
  2. 不会,它不会阻塞并立即返回控制。要并行运行的项在后台线程上完成。

或者还有其他情况发生,是否有人确定呢?

这个问题出现在我实现一个日志类时:

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个回答

72

第一点是正确的;Parallel.ForEach在循环完成前不会返回。如果您不希望出现这种行为,则可以将循环作为Task执行,并在另一个线程上运行它。


谢谢你的提示!你有没有在这种情况下使用“Task”的一小段代码片段?谢谢,保罗。 - Paul Fryer
3
@PaulFryer: Task t = Task.TaskFactory.StartNew(() => {/* Parallel.For goes here */});@PaulFryer 发布的代码是在使用 C# 编程语言中的多线程编程功能。这段代码创建了一个新的任务(Task),并通过任务工厂(TaskFactory)启动该任务,同时将一个 Lambda 表达式作为参数传递给 StartNew 方法。Lambda 表达式中包含需要并行执行的代码,并且可以使用 Parallel.For 方法来实现循环并行化。 - Richard
11
从技术上讲,在并行循环中使用了调用线程。因此,即使在循环阻塞时,它也不会被“浪费”,而是作为工作线程之一被利用。 - Stephen Cleary

12

关于您的更新,对于普通的foreach(),使用StartNew:

这可能不是处理大型集合的最优选择,并且你没有一个点来处理错误。

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

请考虑:

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

啊,说得好。我需要再考虑一下,如果日志服务失败了,如何记录错误 :-) - Paul Fryer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接