C# Parallel.ForEach中的异常堆栈跟踪和聚合

C# Parallel.ForEach中的异常堆栈跟踪和聚合,c#,multithreading,exception,parallel-processing,task-parallel-library,C#,Multithreading,Exception,Parallel Processing,Task Parallel Library,我有一些代码要并行化。它现在看起来像这样: foreach (var item in collection) { if (error) { throw new Exception(); } } Parallel.ForEach(collection, item => { if (error) { throw new Exception(); } }); 异常及其堆栈跟踪保存在日志文件中 并行化后,它将如下所

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

foreach (var item in collection)
{
    if (error)
    {
        throw new Exception();
    }
}
Parallel.ForEach(collection, item =>
{
    if (error)
    {
        throw new Exception();
    }
});
异常及其堆栈跟踪保存在日志文件中

并行化后,它将如下所示:

foreach (var item in collection)
{
    if (error)
    {
        throw new Exception();
    }
}
Parallel.ForEach(collection, item =>
{
    if (error)
    {
        throw new Exception();
    }
});
  • 此异常将如何停止其他项的并行执行?在一个循环线程中遇到错误时,是否有方法停止所有其他执行
  • 这将如何影响异常堆栈跟踪
  • 当抛出异常时,尚未计划的项目的执行将被取消。但是,已计划的项目不会也不能取消。(请记住,这是并行发生的,这就是为什么您首先使用
    parallel
    )它们将一直运行到最后,并且它们自己可能会抛出异常

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



  • 以下代码可用于验证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();
                }
            });
        }
    
    static void TryCatchFunction()
    {
    ConcurrentBag=null;
    int numItemsInBag=0;
    尝试
    {
    错误功能(出袋);
    numItemsInBag=行李计数;
    }
    捕获(例外)
    {
    numItemsInBag=行李计数;
    }
    }
    静态无效错误功能(out ConcurrentBag)
    {
    字符串[]字符串=新字符串[]{“1”、“2”、“3”、“4”、“5”、“6”};
    ConcurrentBag inFunctionBag=新ConcurrentBag();
    袋子=不起作用的袋子;
    Parallel.ForEach(字符串,(str,state)=>
    {
    如果(str==“2”| | str==“4”)
    {
    添加(str);
    抛出新异常();
    }
    });
    }
    
    在双核机器上的方法调用之间,包中的项目数量会有所不同。发生这种情况的原因是,有时异常会取消另一个线程的执行,而有时两者都会运行到完成