前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于任务的异步编程(Task,async,await)

基于任务的异步编程(Task,async,await)

作者头像
宿春磊Charles
发布2022-03-29 09:35:37
3430
发布2022-03-29 09:35:37
举报
文章被收录于专栏:DotNet 致知

这节讲一下比较高级的异步编程用法Task,以及两个异步关键字async和await。

Task是在C#5.0推出的语法,它是基于任务的异步编程语法,是对Thread的升级,也提供了很多API,先看一下Task怎么使用:

代码语言:javascript
复制
 System.Threading.Tasks.Task.Run(() =>
  {
      Console.WriteLine("异步");
  });
  System.Threading.Tasks.Task aTask=new System.Threading.Tasks.Task(() =>
  {
      Console.WriteLine("异步");
  });
  aTask.Start();
  System.Threading.Tasks.Task.Factory.StartNew(() =>
  {
      Console.WriteLine("异步");
  });

Task.Run()可以直接异步运行一个方法,或者使用实例化Task传入委托的方式,通过start()进行启动,再或者使用Task.Factory.StartNew()直接启动。

async,await

为了进一步介绍Task,需要先介绍两个异步有关的关键字async,await

async用在方法的声明,await用于代码语句中。被async标记的方法,称作异步方法。但是,并非整个方法都是异步执行,代码中以await开头标记的代码,才是要真正异步执行的具体内容。这个关键字一般是配合Task来使用的,Task有泛型的形式,标识异步的返回值类型,通过Result()方法获取返回值。这段说明很难理解,下面看代码演示:

代码语言:javascript
复制
static void Main(string[] args)
{
    Console.WriteLine("新建一个异步任务");
    Task<int> task = new Program().GetValue();

    Console.WriteLine("正在计算结果....");
    Console.WriteLine($"运行结果为:{task.Result}");
    Console.WriteLine("任务完成....");
}
public async Task<int> GetValue()
{
    Console.WriteLine("即将开始进行计算...3");
    Console.WriteLine("即将开始进行计算...2");
    Console.WriteLine("即将开始进行计算...1");
    int a= await System.Threading.Tasks.Task.Run(() =>
    {
        int i = 0;
         for (; i < 10; i++)
         {
             Console.WriteLine(i);
         }
         return i;
     });
    Console.WriteLine("结果计算完成....");
    return a;
}

运行结果为:

从运行结果可以看出,程序运行到15行await处后,下一步就跳出了这个方法,回到第6行执行,这也是await的一个特性,异步执行,将主线程执行权交回,也就是说,从15行到25行是在后台线程中执行的,之前的执行都是同步的,之后的执行也是同步的,而且,主线程的脚步没有停下,直到遇到task.Result,Result里边存放着异步方法运行的返回值,运行到这,如果异步没有完成,就会阻塞当前线程,直到异步返回结果。

另外说一点,之前在讲自定义中间件的时候,涉及到过这两个关键词,现在明白了这个用法,可以回去再看一下,应该会对中间件的访问流程有一个更清晰的理解。

ContinueWith

ContinueWith设置Task在执行完原有任务后,再继续执行此方法设置的方法,下面看代码:

代码语言:javascript
复制
 task.ContinueWith((task) =>
  {
      Console.WriteLine("---------------"+task.Result);
  });

这是其中的一个重载,接受一个Action<Task<T>>类型的委托,此处乍一看可能会不解,其实就是把当前执行任务的Task对象传进来了。这样的用法有什么好处呢,运行完了以后,可以直接取Task任务的返回值,不用阻塞线程,当然这是在返回值不是急需的情况下。

CancellationTokenSource

CancellationTokenSource类用于终止一个任务,请先看一下代码:

代码语言:javascript
复制
static void Main(string[] args)
{
    CancellationTokenSource cancellationToken=new CancellationTokenSource();

    Task<int> task= new Program().GetValue(cancellationToken);
    cancellationToken.Cancel();//结束异步任务
    Console.WriteLine("正在计算结果....");

    Console.WriteLine($"运行结果为:{task.Result}");
    Thread.Sleep(1000);
    Console.WriteLine("任务完成....");
}
public Task<int> GetValue(CancellationTokenSource cancellationToken)
{
    Task<int> a = System.Threading.Tasks.Task.Run(() =>
     {
         int i = 0;
         for (; i < 100; i++)
         {
             Console.WriteLine(i);
             Thread.Sleep(500);
         }
         return i;
     },cancellationToken.Token);//传入Token
    Console.WriteLine("结果计算完成....");
    return a;
}

创建一个CancellationTokenSource对象,在Run任务的时候传入一个Token,就能调用Cancel()方法就能终止这个任务,运行结果为:

可以看到报错了,这很正常,因为任务停止了,显然Result是没有值的

最后注意一点,异步不是多线程,可以说异步是基于多线程,但是它们不是等于的关系。

本节到此结束(下节会开一批Linq的讲解,可能会先停更几天,用于准备)...

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet 致知 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CancellationTokenSource
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档