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

问题描述 投票:2回答:1

我正在使用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;
});

据我所知,第一个选项将取消整个块,从而关闭整个管道。我的问题是是否还会取消内部操作并处置所有资源(如果有的话)(打开StreamReaders等),还是最好选择第二个选项,否则我本人可以确保取消并清理所有内容,然后再使用一些方法(铁路编程)将升高的OperationCanceledException沿管道浮动并在需要的地方处理?

c# task-parallel-library tpl-dataflow cancellationtokensource
1个回答
1
投票

这两个选项不相同。

  1. 第一个选项(CancellationToken = _downloadCts.Token)将使processBlockV1块放弃其缓冲区中当前存在的任何消息(其InputCount属性将变为InputCount),并停止接受新消息(调用其0方法将始终返回Post。它不会停止处理当前正在处理的消息。这些将被完全处理,但不会传播到任何链接的块。处理完这些消息后,该块将以取消状态完成(其Post false属性将变为Completion)。

  2. 第二个选项(取消内部操作)对整个块均无效。 Dataflow块可以容忍从其处理功能中抛出的所有Completion,而只需忽略出现故障的项目并继续进行下一项。因此,在取消令牌后,所有发布的消息仍将被处理,并且该区块将继续接受更多消息。它只是不会传播任何东西到它的链接块,因为所有项目都会抛出.Status并被忽略。在特定示例中,将为所有.Status消息调用Canceled方法,因此将对块的完成施加延迟。块的最终状态将是OperationCanceledException

重要的是要知道数据流模块正在认真对待OperationCanceledException的概念。他们将等待所知道的一切停止运行,然后再报告完成。如果您确实希望它们过早完成并留下仍在运行的任务,则必须执行OperationCanceledException之类的技巧。

© www.soinside.com 2019 - 2024. All rights reserved.