是的,您应该在代码中的适当位置手动调用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.");
}
}