繁体   English   中英

如何在第一次异常时取消整个tpl dataFlow?

[英]How to cancel the whole tpl dataFlow on first exception?

考虑以下示例:

        ActionBlock<TimeSpan> ab = new ActionBlock<TimeSpan>(async _ =>
        {
            await Task.Delay(_);
            throw new Exception();
        }, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = Int32.MaxValue });

        ab.Post(TimeSpan.FromSeconds(10d));
        ab.Post(TimeSpan.FromDays(1d));

        await ab.Completion;

不出所料,我在输出窗口中看到10秒后将引发异常,但这不会导致dataFlow完成(等待ab之后的断点。完成不会在1天前命中)。

就我而言,如果单个计算步骤中有异常,我想取消整个dataFlow。

我看不到如何使用tpl dataflow做到这一点...有什么建议吗?

谢谢...

[edit]如Ofir所述,我可以这样做:

        ActionBlock<TimeSpan> ab = new ActionBlock<TimeSpan>(async _ =>
        {
            try
            {
                await Task.Delay(_);
                throw new Exception();// Or any other Task thay may throw an exception.
            }
            catch(Exception)
            {
                cancelTokenSource.Cancel();
                throw;
            }
        }, new ExecutionDataflowBlockOptions() {CancellationToken=cancelTokenSource.Token, MaxDegreeOfParallelism = Int32.MaxValue });

        ab.Post(TimeSpan.FromSeconds(10d));
        ab.Post(TimeSpan.FromDays(1d));

        await ab.Completion;

但这正是我要避免的事情:一次又一次地键入相同的try {} catch……或更糟糕的是:忘记了...;)

我接下来要做的是编写一个替代ActionBlock的构造函数来处理该问题(这将需要一个额外的CancellationTokenSource参数)...我很惊讶这不是直接与数据流一起出现的吗?确实如此吗?

[最终编辑]似乎答案是tpd dataFlow中没有这样的东西 ,而将CancellationTokenSource作为参数的ActionBlock "extension constructor" (in fact a static method)可能是一种解决方法...

您抛出的Exception将使ActionBlock进入故障状态,并将所有要缓冲的消息丢弃,并且不接受更多消息。
对于CancelationToken (可以在ExecutionDataflowBlockOptions提供)也是如此。

当前处理的消息完成后,您将在await ab.Completion上收到AggregateException

Task ,您必须自己照顾已经执行的消息的中止。

为了演示,在您提供的示例中,可以这样实现:

var cancellationTokenSource = new CancellationTokenSource();
var ab = new ActionBlock<TimeSpan>(async _  =>
{
    // await with cancellation token
    await Task.Delay(_, cancellationTokenSource.Token);
    cancellationTokenSource.Cancel();
}, new ExecutionDataflowBlockOptions {CancellationToken = cancellationTokenSource.Token, MaxDegreeOfParallelism = int.MaxValue});

ab.Post(TimeSpan.FromSeconds(10));
ab.Post(TimeSpan.FromSeconds(20));
Thread.Sleep(15000);
cancellationTokenSource.Cancel();
ab.Post(TimeSpan.FromSeconds(100));

try { await ab.Completion; }
catch(TaskCancelationException ex)
{ }

在上述情况下,我们将发布2条消息,这些消息将立即运行。
10秒钟后,第一条消息将导致CancelcancellationTokenSource并导致另一条消息(那延迟20秒)立即完成,并将ActionBlock置于canceled状态。 我们尝试发布的下一条消息不会被接受,也不会执行。

15秒后,我们将在等待completion收到TaskCancelationException

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM