我应该何时调用 CancellationToken.ThrowIfCancellationRequested?
Posted
技术标签:
【中文标题】我应该何时调用 CancellationToken.ThrowIfCancellationRequested?【英文标题】:When should I call CancellationToken.ThrowIfCancellationRequested? 【发布时间】:2021-11-26 18:33:00 【问题描述】:我开发了一个基于 C# 的 Windows 服务,它在几个不同的任务中运行它的所有逻辑。 为了让服务在停止时正常关闭,我使用了一个 CancellationToken,它被传递给任何接受一个(主要来自我正在使用的第 3 方库)的函数,以便在完成之前中止处理。
我注意到,在调用函数时请求取消时,这些函数都不会抛出 OperationCanceledException
,因此我的应用程序只是继续执行,直到我稍后在代码中的其他地方调用 ThrowIfCancellationRequested()
。我应该在调用每个函数后手动调用ThrowIfCancellationRequested()
以确保任务尽快停止,还是我应该在我自己的代码中准确地调用ThrowIfCancellationRequested()
?
【问题讨论】:
【参考方案1】:是的,您应该在代码中的适当位置手动调用ThrowIfCancellationRequested()
(适当的位置由您作为程序员确定)。
考虑以下简单的作业处理函数示例,该函数从队列中读取作业并对其进行处理。 cmets 说明了开发人员在决定是否检查取消时可能会经历的那种思考。
请注意,您是对的 - 接受令牌的标准框架函数不会抛出取消异常 - 它们只会提前返回,因此您必须自己检查取消。
public async Task DoWork(CancellationToken token)
while(true)
// It is safe to check the token here, as we have not started any work
token.ThrowIfCancellationRequested();
var nextJob = GetNextJob();
// We can check the token here, because we have not
// made any changes to the system.
token.ThrowIfCancellationRequested();
var jobInfo = httpClient.Get($"job/info/nextJob.Id", token);
// We can check the token here, because we have not
// made any changes to the system.
// Note that HttpClient won't throw an exception
// if the token is cancelled - it will just return early,
// so we must check for cancellation ourselves.
token.ThrowIfCancellationRequested();
// The following code is a critical section - we are going to start
// modifying various databases and things, so don't check for
// cancellation until we have done it all.
ModifySystem1(nextJob);
ModifySystem2(nextJob);
ModifySystem3(nextJob);
// We *could* check for cancellation here as it is safe, but since
// we have already done all the required work *and* marking a job
// as complete is very fast, there is not a lot of point.
MarkJobAsCompleted(nextJob);
最后,您可能不想从您的代码中泄露取消异常,因为它们不是“真正的”异常 - 只要有人停止您的服务,它们就会发生。
您可以使用如下异常过滤器捕获异常:
public async Task DoWork(CancellationToken token)
try
while(true)
// Do job processing
catch (OperationCanceledException e) when (e.CancellationToken == token)
Log.Info("Operation cancelled because service is shutting down.");
catch (Exception e)
Log.Error(e, "Ok - this is actually a real exception. Oh dear.");
【讨论】:
以上是关于我应该何时调用 CancellationToken.ThrowIfCancellationRequested?的主要内容,如果未能解决你的问题,请参考以下文章
我是不是应该始终将 CancellationToken 添加到我的控制器操作中?
在键盘事件中使用 CancellationToken 调用 Task.Delay 时出现 TaskCanceledException
我应该何时调用 StateHasChanged 以及 Blazor 何时自动拦截某些更改?
我们应该将 CancellationToken 与 MVC/Web API 控制器一起使用吗?
为 HTML 控件提供建议:我应该何时调用 DispEventUnadvise?
编码自定义 SplitViewController - 我应该何时调用 viewWillAppear、viewDidAppear 等...?