从Parallel.ForEach抛出的未处理OperationCanceledException异常

7

我正在尝试允许取消Parallel.ForEach循环。根据这篇MSDN文章所述,这是可能的,我正在按照他们的编程方式进行操作。

// Tokens for cancellation 
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;

try
{
    Parallel.ForEach(queries, po, (currentQuery) =>
    {
        // Execute query
        ExecuteQuery(currentQuery);

        // Throw exception if cancelled 
        po.CancellationToken.ThrowIfCancellationRequested(); // ***
    }); 
}
catch (OperationCanceledException cancelException)
{
    Console.WriteLine(cancelException.Message);
}

然而,当我从一个用户可访问的函数中调用 cts.Cancel(); 时,应用程序会在上面标有星号的行崩溃,并显示以下错误:
System.OperationCanceledException was unhandled by user code
  Message=The operation was canceled.
  Source=mscorlib
  StackTrace:
   at System.Threading.CancellationToken.ThrowIfCancellationRequested()
   at CraigslistReader.SearchObject.<>c__DisplayClass7.<bw_DoWork>b__5(Query currentQuery) in {PATH}:line 286
   at System.Threading.Tasks.Parallel.<>c__DisplayClass2d`2.<ForEachWorker>b__23(Int32 i)
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
InnerException: 

我在那里已经设置了异常处理程序,所以我不理解为什么会崩溃。有任何想法吗?

我没有看到你所描述的问题,catch 对我来说很好用。你能否发布一个完整但简短的代码,以展示你的问题? - svick
我不认为这个应用程序已经崩溃,至少没有出现过这个异常。要么你的应用程序没有崩溃(你如何知道它已经崩溃了?),要么这不是正在发生的最后一个异常。 - usr
@usr 是的,你说得对。我在调试器中运行它时,当我看到异常停止运行时,我以为这是一个会崩溃应用程序的异常。我不知道有些异常并不会导致崩溃。 - Doug
我相信这通常被称为“第一次机会异常”。正如您所指出的那样,它并不意味着会使应用程序崩溃,而只是一个调试概念。 - BlakeH
1个回答

2
问题在于po.CancellationToken.ThrowIfCancellationRequested();明确地抛出了一个未处理的异常。可能会在Parrallel.ForEach()调用周围有异常处理程序,但是异常不在lambda表达式内部处理。 要么删除该行,要么在lambda表达式中添加异常处理程序,这样它应该可以正常工作。
有关更多信息,请参见取消任务时抛出异常

我也遇到了同样的问题。那么如何正确处理它呢? - Syaiful Nizam Yahya
@publicENEMY 要么在lambda函数中捕获异常,要么不要调用ThrowIfCancellationRequested()。抛出异常是该方法的工作原理。 - akton
@akton,我一直看到“在Lambda函数中捕获异常”。我该怎么做呢?你是说我应该在ThrowIfCancellationRequested()句子上使用try / catch块吗? - Syaiful Nizam Yahya
1
@publicENEMY 在调用 ThrowIfCancellationRequested() 的地方加上 try/catch。 - akton
不确定这是否与OP中描述的情况相同,但我遇到了类似的问题。我没有在Parallel.ForEach循环内部使用ThrowIfCancellationRequested,但我确实在外部取消了它。我将循环包裹在try/catch中(用于捕获任何异常)。然而,异常没有被捕获,导致我的WPF应用程序崩溃。解决问题的方法是从调用循环的函数中移除async。它被错误地标记为async void。我不知道为什么会发生这种情况,但这可能对其他遇到类似问题的人有所帮助。 - undefined
显示剩余7条评论

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