https://technet.microsoft.com/zh-cn/library/dd460688(v=vs.100)
处理 PLINQ 查询中的异常
本主题中的第一个示例演示如何处理在 PLINQ 查询执行时可能从中引发的 System.AggregateException。 第二个示例演示如何将 try-catch 块放在委托内,尽可能靠近将会引发异常的位置。 通过这种方式,一旦发生异常,您就可以捕获它们并且可能继续执行查询。 如果允许异常向上冒泡回到联接线程,则查询操作也许可以在引发异常后继续处理一些项目。
在某些情况下,当 PLINQ 回退到顺序执行并发生异常时,可能会直接传播该异常,而不是包装到 AggregateException 中。 此外,始终可以直接传播ThreadAbortException。
注意 |
---|
当启用“仅我的代码”时,Visual Studio 将在引发异常的行上中断运行,并显示错误消息“异常未由用户代码处理”。此错误是良性的。 可以按 F5 从中断处继续运行,并查看在以下示例中演示的异常处理行为。 若要阻止 Visual Studio 在出现第一个错误时中断运行,只需在“工具”->“选项”->“调试”->“常规”下取消选中“仅我的代码”复选框即可。 本示例旨在演示用法,运行速度可能不如等效的顺序 LINQ to Objects 查询快。 有关加速的更多信息,请参见了解 PLINQ 中的加速。 |
此示例演示如何将 try-catch 块放在执行查询以捕获任何引发的 System.AggregateException 的代码的周围。
// Paste into PLINQDataSample class. static void PLINQExceptions_1() { // Using the raw string array here. See PLINQ Data Sample. string[] customers = GetCustomersAsStrings().ToArray(); // First, we must simulate some currupt input. customers[54] = "###"; var parallelQuery = from cust in customers.AsParallel() let fields = cust.Split(',') where fields[3].StartsWith("C") //throw indexoutofrange select new { city = fields[3], thread = Thread.CurrentThread.ManagedThreadId }; try { // We use ForAll although it doesn't really improve performance // since all output is serialized through the Console. parallelQuery.ForAll(e => Console.WriteLine("City: {0}, Thread:{1}", e.city, e.thread)); } // In this design, we stop query processing when the exception occurs. catch (AggregateException e) { foreach (var ex in e.InnerExceptions) { Console.WriteLine(ex.Message); if (ex is IndexOutOfRangeException) Console.WriteLine("The data source is corrupt. Query stopped."); } } }
在此示例中,查询在引发异常后无法继续。 到应用程序代码捕获异常时,PLINQ 已经在所有线程上停止了查询。
下面的示例演示如何将 try-catch 块放在委托中,以便能够捕获异常并继续执行查询。
// Paste into PLINQDataSample class. static void PLINQExceptions_2() { var customers = GetCustomersAsStrings().ToArray(); // Using the raw string array here. // First, we must simulate some currupt input customers[54] = "###"; // Create a delegate with a lambda expression. // Assume that in this app, we expect malformed data // occasionally and by design we just report it and continue. Func<string[], string, bool> isTrue = (f, c) => { try { string s = f[3]; return s.StartsWith(c); } catch (IndexOutOfRangeException e) { Console.WriteLine("Malformed cust: {0}", f); return false; } }; // Using the raw string array here var parallelQuery = from cust in customers.AsParallel() let fields = cust.Split(',') where isTrue(fields, "C") //use a named delegate with a try-catch select new { city = fields[3] }; try { // We use ForAll although it doesn't really improve performance // since all output must be serialized through the Console. parallelQuery.ForAll(e => Console.WriteLine(e.city)); } // IndexOutOfRangeException will not bubble up // because we handle it where it is thrown. catch (AggregateException e) { foreach (var ex in e.InnerExceptions) Console.WriteLine(ex.Message); } }