目录
介绍:
简单举例
IsCancellationRequested
ThrowIfCancellationRequested
在控制器中使用
通过异步方法的参数使用cancellationToken
api结合ThrowIfCancellationRequested()
CancellationToken是.NET中用于协调取消操作的结构。它通常用于多线程操作,例如任务和线程等。当你启动一个新的任务或线程时,你可以传递一个CancellationToken给它,然后在其他线程中,你可以使用这个token来请求取消操作。
例如,你可能有一个长时间运行的任务,你希望用户能够取消。你可以传递一个CancellationToken给这个任务,然后在任务的代码中定期检查IsCancellationRequested属性,或者调用ThrowIfCancellationRequested方法。如果用户请求取消操作,那么你的任务代码将能够响应这个请求。
下面用几个简单的例子来使用IsCancellationRequested属性与ThrowIfCancellationRequested方法,更直观的展示他们的用法,在CancellationToken中我们可以直接使用Cancel()方法来取消操作,但是为了演示方便,我们下面的例子使用的都是CancelAfter()来进行延迟关闭
我们创建一个CancellationTokenSource对象,然后通过CancelAfter(5000)设置一个5秒的取消延迟。然后写一个无限循环,在循环中打印"任务执行中!"(假装在执行任务)!5秒钟后,CancelAfter方法会触发取消请求,这时cts.IsCancellationRequested属性会变为true。然后就会打印"任务被取消!",并跳出循环。如下图所示
public static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(5000);
while (true)
{
Console.WriteLine("任务执行中!");
if (cts.IsCancellationRequested)
{
Console.WriteLine("任务被取消!");
break;
}
}
}
将刚刚的代码修改一下,换成使用ThrowIfCancellationRequested(),方法执行后,还是会在控制台打印"任务执行中!",5秒钟后,CancelAfter方法触发取消请求,于是执行到ThrowIfCancellationRequested()的时候抛出了一个异常,操作被取消了!
public static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(5000);
while (true)
{
Console.WriteLine("任务执行中!");
cts.Token.ThrowIfCancellationRequested();
}
}
在ASP.NET Core中,CancellationToken是一个可选参数,可以被添加到控制器的动作方法中。当客户端请求被关闭或取消时,ASP.NET Core会自动取消关联的CancellationToken。
这是因为ASP.NET Core的内部机制。当客户端发送一个请求到服务器,服务器会为这个请求创建一个CancellationToken,并且当客户端关闭连接时,服务器会自动调用CancellationToken的Cancel方法,以便通知应用程序请求已经被取消。
因此,我们可以直接在Controller中加入CancellationToken参数,如下图,这是我的一个ai识别项目,他会将收到的图片作为请求体,调用我部署在服务器上的ai识别api,如果用户通过网页,上传了一张图片进行ai识别,但是因为识别时间太长了,他不想等待并且把网页关了,此时我的后台还在傻傻的进行图片识别,势必会造成资源的浪费,下面我们就来改造一下他!
在上面我们调用PutPhoto的时候参数中添加了controller中拿到的cancellationToken,因此这边方法中的参数也加上CancellationToken cancellationToken来接,如下图,上面的代码都是对请求体进行组装,我们重点看最下面这一行。
var response = await client.ExecuteAsync(request);
Ctrl + 左键 点击 ExecuteAsync
我们查看一下RestClient的ExecuteAsync方法,可以看见他是有一个可选参数cancellationToken,这意味这我们又可以直接把在controller中拿到的cancellationToken继续丢进去。
因此,我们把最后一句代码改成,然后我在执行这一行代码之前,打一个断点。
var response = await client.ExecuteAsync(request,cancellationToken);
在执行这行代码之前,我将浏览器关闭了,然后再继续下一步
我们在返回结果中看到,错误信息中提示:A task was canceled,一个任务被取消,其实哪怕是我的请求在进行中,只要一关闭浏览器,任务就会立马结束,但是因为我服务器的响应速度太快了,不好实现这个演示!
ThrowIfCancellationRequested()
假设你现在的场景中异步方法并没有cancellationToken参数,那么你可以结合我们上面演示中使用的ThrowIfCancellationRequested()
来取消操作。请求取消时,它会抛出一个异常OperationCanceledException
,这样你就可以在你的代码中捕获这个异常并进行相应的处理。
try
{
var response = await client.ExecuteAsync(request);
// 在这里检查取消标记
cancellationToken.ThrowIfCancellationRequested();
}
catch (OperationCanceledException)
{
// 这里处理取消操作的逻辑
}
要注意的是,这种方式只能取消还没有开始的操作。如果ExecuteAsync
方法已经开始执行,那么这个取消请求就无法停止它,因此如果异步方法可以支持传参cancellationToken的话,我们还是首选使用传参的方法!