取消TPL数据流块的正确方法

Correct way to cancel TPL data flow block

我正在使用 TPL 块来执行可能被用户取消的操作: 我想出了两个选项,首先我取消整个块但不取消块内的操作,如下所示:

_downloadCts = new CancellationTokenSource();

var processBlockV1 = new TransformBlock<int, List<int>>(construct =>
{
    List<int> properties = GetPropertiesMethod(construct );
    var entities = properties
        .AsParallel()
        .Select(DoSometheningWithData)
        .ToList();
    return entities;
}, new ExecutionDataflowBlockOptions() { CancellationToken = _downloadCts.Token });

第二次我取消内部操作,但不是块本身:

var processBlockV2 = new TransformBlock<int, List<int>>(construct =>
{
    List<int> properties = GetPropertiesMethod(construct);
    var entities = properties
        .AsParallel().WithCancellation(_downloadCts.Token)
        .Select(DoSometheningWithData)
        .ToList();
    return entities;
});

据我了解,第一个选项将取消整个块,从而关闭整个管道。我的问题是它是否也会取消内部操作并处理所有资源(如果有)(打开 StreamReader 等)还是选择第二个选项更好然后我自己可以确保一切都被取消和清理然后我可以使用一些方法(铁路编程)将 OperationCanceledException 漂浮在管道中并在我想要的地方处理它?

这两个选项不等价。

  1. 第一个选项 (CancellationToken = _downloadCts.Token) 将使 processBlockV1 块丢弃当前在其缓冲区中的任何消息(它的 InputCount property will become 0), and stop accepting new messages (invoking its Post method will invariably return false). It will not stop processing the messages that are currently in progress though. These will be processed fully, but will not be propagated to any linked blocks. After these messages are processed, the block will complete in a canceled state (its Completion.Status 属性 将变为 Canceled).

  2. 第二个选项(取消内部操作)对整个块没有影响。数据流块容忍从其处理函数抛出的任何 OperationCanceledException,并且只忽略故障项并继续下一个。所以在令牌取消后,所有发布的消息仍然会被处理,块将继续接受更多。它只是不会将任何内容传播到它的链接块,因为所有项目都会抛出 OperationCanceledException 并被忽略。在具体示例中,将为所有 construct 消息调用 GetPropertiesMethod 方法,因此会对块的完成施加延迟。块的最终状态将是 RanToCompletion.

重要的是要知道数据流块正在认真对待 Completion 的概念。在报告完成之前,他们将等待他们知道的一切停止 运行。如果您确实希望他们过早完成并留下仍然 运行 的任务,您将不得不采取 .

之类的技巧