• 在C#中使用 CancellationToken 处理异步任务


    在 .NET Core 中使用异步编程已经很普遍了, 你在项目中随处可见 async 和 await,它简化了异步操作,允许开发人员,使用同步的方式编写异步代码,你会发现在大部分的异步方法中,都提供了CancellationToken参数,本文主要介绍下 CancellationTokenSource 和 CancellationToken在异步任务中的使用。

    手动取消任务

    创建一个 CancellationTokenSource,然后调用异步方法时,传入 CancellationToken,它是一个轻量级对象,可以通知请求是否已取消,我们可以手动调用 cts.Cancel() 来取消任务,为了方面演示,这里我有用到局部方法。

    static async Task Main(string[] args)
    {
       async Task Execute(CancellationToken token)
       {
       	await Task.Delay(3000, token);
       	Console.WriteLine("Executed");
       } 
    
       CancellationTokenSource cts = new CancellationTokenSource();  
    
       _ = Execute(cts.Token);
    
       // 手动取消任务
       cts.Cancel();  
    
       Console.ReadKey();
    }   
    

    定时取消任务

    创建 CancellationTokenSource 的时候,可以传入时间(毫秒或者Timespan), 通过它我们可以在等待一段时间后,自动取消任务。

     CancellationTokenSource cts = new CancellationTokenSource(1000);  
    
    _ = Execute(cts.Token);  
    
    Console.ReadKey();
    

    我们也可以调用 cts.CancelAfter(1000), 它会在1s后取消任务。

    cts.CancelAfter(1000);
    

    CancellationToken 注册回调

    我们可以调用 Register()方法,注册Token取消的回调,参数需要传入 Action 委托。

      CancellationTokenSource cts = new CancellationTokenSource(1000);
    
    cts.Token.Register(() => Console.WriteLine("任务已取消!"));
    
    // 开始异步任务
    _ = Execute(cts.Token);    
    
    Console.ReadKey();
    

    Register() 注册回调后,返回一个 CancellationTokenRegistration 对象,同样的,你可以在回调函数执行前,移除注册回调,就像这样:

    cts.Token.Register(() => Console.WriteLine("任务已取消!")).Unregister();
    

    在 HttpClient 中使用

    同样,你可以在 HttpClient 中使用传入 CancellationToken (或者使用HttpClient的Timeout属性),超时后,它会抛出一个 TaskCanceledException 的异常:

      CancellationTokenSource cts = new CancellationTokenSource(10);  
    
    _ = await new HttpClient().GetAsync("https://www.youtube.com/",cts.Token); 
    
    Console.ReadKey();
    

    在 WebAPI中使用

    我创建了一个 WebAPI 项目,其中的控制器代码如下,等待了5s,然后进行输出信息。

     [HttpGet]
    public async Task<IActionResult> Index()
    {
    	await Task.Delay(5000);
    	Console.WriteLine("Executed");
    	return Ok();
    }
    

    启动项目后,我们在浏览器页面上访问接口,在第一次访问接口等待响应时,我刷新一次了页面,现在程序的输出信息如下:

    说明前台页面刷新后,后台并没有做取消操作,执行了两次!

    我们可以把程序改成这样,传入 CancellationToken

    [HttpGet]
    public async Task<IActionResult> Index(CancellationToken token)
    {
    	await Task.Delay(5000,token);
    	Console.WriteLine("Executed");
    	return Ok();
    }
    

    现在在浏览器访问页面,同样的,第一次还未返回是,我们刷新一次页面,程序输出如下:

    只有一次输出,第一次请求抛出了一次 TaskCanceledException 异常,没有继续执行后边的逻辑,当然你可以捕获这个异常,返回更友好的提示!

    欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享。

  • 相关阅读:
    C# asp:Repeater DataSource List<T>
    MySQL DATE_FORMATE函数内置字符集的坑_转小叶子爹
    MySQL count(distinct) 逻辑的一个bug
    org.hibernate.PersistentObjectException: detached entity passed to persist:
    CGLIB Enhancement failed
    firstResult/maxResults specified on polymorphic query;
    Last packet sent to the server was 0 ms ago.
    MySql Error Code: 2006 – MySQl
    InnoDB: Error: auto-extending data file ./ibdata1 is of a different size
    mysql 大数据量分页处理
  • 原文地址:https://www.cnblogs.com/myshowtime/p/14545360.html
Copyright © 2020-2023  润新知