考虑以下示例:
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完成(await ab.Completion之后的断点在1天之前不会被命中)。
就我而言,如果在一个计算步骤中出现异常,我想取消整个dataFlow。
我无法看到如何使用tpl数据流... 有什么建议吗?
...谢谢
[编辑]正如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 {}一次又一次地抓住......或者更糟:忘掉它......;)
接下来我要做的就是为ActionBlock的构造函数编写一个替换来处理它(它需要额外的CancellationTokenSource参数)... 我很惊讶这不直接来自数据流......真的是这样吗?
[最终编辑]
似乎答案是在tpd dataFlow 中没有这样的东西,并且ActionBlock "extension constructor" (in fact a static method)
接受CancellationTokenSource作为参数将是一种可能的解决方法......
答案 0 :(得分:4)
您投掷的Exception
会将ActionBlock
置于故障状态
并将删除所有缓冲的邮件,并且不会接受更多邮件
对于CancelationToken
(可以在ExecutionDataflowBlockOptions
)
完成当前处理的消息后,您将在AggregateException
上收到await ab.Completion
。
与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秒后,第一条消息将导致Cancel
cancellationTokenSource
并导致另一条消息(延迟20秒)立即完成,并将ActionBlock
置于取消状态。
我们尝试发布的下一条消息不被接受,也不会被执行。
15秒后,我们会在等待TaskCancelationException
时获得completion
。