使用取消令牌为用户定义的函数设置超时

Posted

技术标签:

【中文标题】使用取消令牌为用户定义的函数设置超时【英文标题】:Set timeout for user defined function using cancelation token 【发布时间】:2020-10-27 23:36:56 【问题描述】:

如果任务持续时间超过 3 秒,我想取消它。

第一次尝试:

public static async Task DoSomething()

    await Task.Delay(10000);


var task1 = DoSomething();
var task2 = Task.Delay(3000);

Task.WaitAny(task1, task2);

第二次尝试:

我尝试使用cancellationToken,但它似乎不起作用。它等待函数 10 秒,它似乎忽略了 3 秒延迟取消。

var cts = new CancellationTokenSource();
var token = cts.Token;
cts.CancelAfter(TimeSpan.FromSeconds(3));

await Task.Run(async () => await DoSomething(), token);

有人可以帮助我使用cancellationToken 实现此类功能吗?

【问题讨论】:

在 .NET is cooperative 中取消。如果它支持取消,您可以取消某些东西,否则,您不能。您可以取消等待操作,就像您在示例中所做的那样,但不能取消操作本身。 哦,原来如此,谢谢你的回答,所以我只能使用取消令牌如果函数本身支持它 是的,Tigran,没错。也恭喜你战胜了 Mikhail Botvinnik! ?????? 【参考方案1】:

您需要将CancellationToken 传递给DoSomething 并在那里使用它:

public static async Task DoSomething(CancellationToken t)

    await Task.Delay(10000, t);


var cts = new CancellationTokenSource();
var token = cts.Token;
cts.CancelAfter(TimeSpan.FromSeconds(3));
try

    await Task.Run(async () => await DoSomething(token), token);

catch (OperationCanceledException ex)

    // canceled

来自docs:

当任务实例观察到用户代码抛出的 OperationCanceledException 时,它会将异常的标记与其关联的标记(传递给创建任务的 API 的标记)进行比较。如果它们相同并且令牌的 IsCancellationRequested 属性返回 true,则任务将此解释为确认取消并转换到 Canceled 状态。如果您不使用 Wait 或 WaitAll 方法来等待任务,则任务只是将其状态设置为 Canceled。

但似乎Task 转换为Canceled 与是否提供相同的令牌无关。

我发现将令牌传递给Task.Run 与否之间的唯一区别是,如果在任务开始执行之前请求取消,则任务不会执行,而是设置为Canceled 状态并抛出一个@ 987654329@ 异常。

【讨论】:

感谢您的回答,但这不是我想要的。您正在调用本机具有参数取消令牌的函数 task.delay,如果函数正在执行一些不支持取消令牌的操作 哦,Theodor Zoulias 已经回答了我的问题

以上是关于使用取消令牌为用户定义的函数设置超时的主要内容,如果未能解决你的问题,请参考以下文章

Polly Timeout 乐观使用 HttpClientFactory。如何使用取消令牌?

AngularJS取消超时

如何为查询执行设置语句超时

区分用户取消超时

我想在使用 kotlin 协程的 android 超时后取消一个函数,但它不起作用

CancellationToken 不能使用零超时