了解 ActionBlock 中的异常处理

Understanding exception handling in ActionBlock

有人可以解释为什么当我们等待操作块完成时第一个代码块会抛出而第二个代码块不会吗?没有任何数据流块链接,因此不需要传播。

ActionBlock 定义 1:

ActionBlock<int> workerBlock = new ActionBlock<int>(async (i) =>
{
    await Task.Delay(1);
    throw new OperationCanceledException();
});

ActionBlock 定义 2:

ActionBlock<int> workerBlock = new ActionBlock<int>(async (i) =>
{
    await ExceptionThrower1();
});


private static async Task ExceptionThrower1()
{
    CancellationTokenSource source= new CancellationTokenSource();
    source.CancelAfter(100);
    await ExceptionThrower2(source.Token);
}

private static async Task ExceptionThrower2(CancellationToken token)
{
    await Task.Delay(1000);
    try
    {
        token.ThrowIfCancellationRequested();
    }
    catch (OperationCanceledException e)
    {
        Console.WriteLine(e);
        throw;
    }
}

测试程序:

workerBlock.SendAsync(1).GetAwaiter().GetResult();
workerBlock.SendAsync(1).GetAwaiter().GetResult();
workerBlock.SendAsync(1).GetAwaiter().GetResult();

workerBlock.Complete();
workerBlock.Completion.GetAwaiter().GetResult();
Console.WriteLine("Done");

如果我使用第一个定义,"Done" 不会被打印出来,因为等待完成会抛出异常。在第二个定义中,"Done" 被打印出来,尽管我可以在 ExceptionThrower2 中看到异常被打印出来。

基于这篇博文 - https://blogs.msdn.microsoft.com/pfxteam/2011/11/09/exception-handling-in-tpl-dataflow-networks/ 即使是第二个也应该考虑未处理的异常并在完成时抛出,对吗?

尝试

ActionBlock<int> workerBlock = new ActionBlock<int>((i) =>
{
    ExceptionThrower1().Wait();
});

ActionBlock 已经处理了异步的东西;添加额外的层似乎吞没了你的异常。

我无法复制您描述的行为,在我的情况下每次都会打印 "Done"。但是,OperationCanceledException 属于 "Exceptions That Indicate Cooperative Cancellation" 类别,请查看 Exception Handling (Task Parallel Library) 并搜索 OperationCanceledException。