【问题标题】:Exception stack trace and aggregation in Parallel.ForEachParallel.ForEach 中的异常堆栈跟踪和聚合
【发布时间】:2016-06-01 16:57:35
【问题描述】:

我有一些代码要并行化。它目前看起来像这样:

foreach (var item in collection)
{
    if (error)
    {
        throw new Exception();
    }
}

异常及其堆栈跟踪保存在日志文件中。

并行化后,它看起来像这样:

Parallel.ForEach(collection, item =>
{
    if (error)
    {
        throw new Exception();
    }
});
  1. 此异常将如何停止其他项目的并行执行?一旦在一个循环线程中遇到错误,有没有办法停止所有其他执行?
  2. 这将如何影响异常堆栈跟踪?

【问题讨论】:

    标签: c# multithreading exception parallel-processing task-parallel-library


    【解决方案1】:
    1. 当抛出异常时,将取消尚未计划的项目的执行。但是,已经安排好的项目不会也不能取消。 (请记住,这是并行发生的,这就是您首先使用Parallel 的原因。)它们将运行到最后,并且自己可能会抛出异常。

    2. 因此,并行循环中可能会引发多个异常。这就是为什么它们总是被包裹在AggregateException 中,即使异常只被抛出一次。您可以捕获 AggregateException 并通过其 InnerExceptions 属性进行枚举,该属性包含所有抛出的异常及其堆栈跟踪:


    try
    {
        Parallel.ForEach(collection, item =>
        {
            if (error)
            {
                throw new Exception();
            }
        });
    }
    catch (AggregateException ex)
    {
        foreach (var exception in ex.InnerExceptions)
        {
            // do something       
        }
    }
    

    【讨论】:

      【解决方案2】:

      以下代码可用于验证 Evk 答案第一部分中讨论的行为:

          static void TryCatchFunction()
          {
              ConcurrentBag<string> bag = null;
              int numItemsInBag = 0;
              try
              {
                  ErrorFunction(out bag);
                  numItemsInBag = bag.Count;
              }
              catch (Exception)
              {
                  numItemsInBag = bag.Count;
              }
          }
      
          static void ErrorFunction(out ConcurrentBag<string> bag)
          {
              string[] strings = new string[] { "1", "2", "3", "4", "5", "6" };
              ConcurrentBag<string> inFunctionBag = new ConcurrentBag<string>();
              bag = inFunctionBag;
      
              Parallel.ForEach(strings, (str, state) =>
              {
                  if (str == "2" || str == "4")
                  {
                      inFunctionBag.Add(str);
                      throw new Exception();
                  }
              });
          }
      

      在双核机器上的方法调用之间,包中的物品数量会有所不同。发生这种情况是因为有时异常会取消另一个线程的执行,而其他时间则都运行直到完成。

      【讨论】:

        猜你喜欢
        • 2011-01-05
        • 1970-01-01
        • 2017-08-06
        • 2010-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        相关资源
        最近更新 更多