2.2异步编程

简介: .net core异步编程

2.2异步编程

用async关键字修饰方法后,就变成了异步方法。需要注意几点:

  • 异步方法返回值一般是Task<T>
  • 约定异步方法名字以Async为结尾。
  • 如果异步方法没有返回值,最好把返回值声明为非泛型的Task类型。
  • 调用泛型异步方法时,一般在前面加上await,这样方法调用的返回值就是T类型。
  • 如果一个方法中有await调用,则方法必须声明为async。

await关键字的意思是:调用异步方法,等异步方法执行结束后再继续向下执行。如果不加await,则不等待异步方法执行结束,就向下执行。

asyncTask<int>DownloadAsync(stringurl, stringdestFilePath)

{

   usingHttpClienthttpClient=newHttpClient();

   stringbody=awaithttpClient.GetStringAsync(url);

   awaitFile.WriteAllTextAsync(destFilePath, body);

   returnbody.Length;

}

Console.WriteLine("开始下载人邮社网站");

inti1=awaitDownloadAsync("https://www.ptpress.com.cn", "d:/ptpress.html");

Console.WriteLine($"下载完成,长度{i1}");

async异步方法的本质是:在对异步方法进行await调用时的等待时间(比如等待下载),会把当前的线程返回到线程池,等异步方法调用结束后,再从线程池中取出一个线程执行后面的代码。

使用async异步方法要用多任务的概念,如果是一个任务,则使用常规的方法更好。例如餐厅客人叫服务员点菜,当来了多个客人时,某个客人叫服务员来点菜,服务员将菜单给到这个客人,然后不需要一直等着,等到这个客人点菜成功,再叫服务员,这个时候服务员拿着点完的菜单交给厨师。这样做的好处是,这个服务员可以在某个客人点菜的时候,去服务其他顾客。

异步方法使用的技术是线程池,不等通于多线程。

  • 有async无await

对于async方法,编译器会把代码根据await调用分为若干片段,对于不同的片段使用状态机的方式切换执行。

//这个虽然是async方法,内部并没有await,它的内部并没有将任务放到其他线程中去执行

//这样写和普通方法一样

staticasyncTask<decimal>CalcAsync(intn)

{

   Console.WriteLine("CalcAsync:"+Thread.CurrentThread.ManagedThreadId);

   decimalresult=1;

   Randomrand=newRandom();

   for (inti=0; i<n*n; i++)

   {

       result=result+ (decimal)rand.NextDouble();

   }

   returnresult;

}

//使用Task.Run方法,把要执行的代码以委托的形式传递给Task.Run,这样系统会从线程池中取出一个线程去执行代码

//这样才实现了异步

asyncTask<decimal>CalcAsync(intn)

{

   Console.WriteLine("CalcAsync:"+Thread.CurrentThread.ManagedThreadId);

   returnawaitTask.Run(() => {

       Console.WriteLine("Task.Run:"+Thread.CurrentThread.ManagedThreadId);

       decimalresult=1;

       Randomrand=newRandom();

       for (inti=0; i<n*n; i++)

       {

           result=result+ (decimal)rand.NextDouble();

       }

       returnresult;

   });

}

//由此可见:

//异步方法的定义中,也需要使用线程池的操作

//在调用异步方法使用await时,await有2个作用:

//1、等待异步方法执行结束再往下执行,因为异步方法的定义中使用了线程池操作(Task.Run),按照正常的执行程序,他会在新线程中执行,而不会等待其执行完成,所以在线程池操作前面也加了await以示和普通线程池操作的区别。

//2、会自动将Task<T>类型的返回值识别为T类型

只要返回值是Task类型,就可以使用await关键字对其进行调用,而不用管是否用async修饰

  • 无async修饰符

如果一个异步方法只是对别的异步方法进行简单调用,无太多复杂逻辑(如获取异步方法的返回值并做处理),则可以直接去掉async修饰符

对于使用async的异步方法,编译器会负责将返回值转换为Task对象(reurn 3 自动转换为Task<int>),但是不带async修饰符的异步方法,需要自己自定义Task对象。

strings1=awaitReadFileAsync(1);

Console.WriteLine(s1);

Task<string>ReadFileAsync(intnum)

{

   switch (num)

   {

       case1:

           returnFile.ReadAllTextAsync("d:/1.txt"); //返回Task对象

       case2:

           returnFile.ReadAllTextAsync("d:/2.txt");

       default:

           returnTask.CompleterTask;//返回Task对象,需要自定义,不能直接return,因为无async修饰

                                     //public static Task CompletedTask { get; }

   }

}

重要问题:

  1. 有异步方法,建议使用异步方法
  2. 由于某些原因,有的方法不能被async修饰,那么在方法内就不能用await来调用异步方法了,也就是不能自动将Task<T>类型的返回值识别为T类型。对于Task<T>返回值类型,可以使用Result属性或者GetAwaiter().GetResult方法来等待异步执行结束后获取返回值。对于Task返回值类型,可以使用Wait方法来调用异步方法并等待任务结束,但不推荐这样,会造成阻塞调用线程。

strings1=File.ReadAllTextAsync("./1.txt").Result;

strings2=File.ReadAllTextAsync("./1.txt").GetAwaiter().GetResult();

File.ReadAllTextAsync("./1.txt").Wait();

  1. 异步方法的暂停

usingHttpClienthttpClient=newHttpClient();

strings1=awaithttpClient.GetStringAsync("https://www.ptpress.com.cn");

awaitTask.Delay(3000);//不要使用Thread.sleep会阻塞调用线程

strings2=awaithttpClient.GetStringAsync("https://www.rymooc.com");

  1. 异步方法中如果有CancellationToken参数,则可以使用该对象提前终止操作。
  2. 可以使用Task.WhenAll同时等待多个Task的执行结束。另外也有Task.WhenAny只要有一个任务完成,代码就向下执行

Task<string>t1=File.ReadAllTextAsync("d:/1.txt");

Task<string>t2=File.ReadAllTextAsync("d:/2.txt");

Task<string>t3=File.ReadAllTextAsync("d:/3.txt");

string[] results=awaitTask.WhenAll(t1, t2, t3);

strings1=results[0];

strings2=results[1];

strings3=results[2];

  1. 接口中或者抽象方法不能使用async修饰符,可以把这些方法的返回值设置为Task类型,在具体实现中可以添加async关键字修饰。
相关文章
|
7月前
|
Java API Go
异步编程 - 01 漫谈异步编程发展史
异步编程 - 01 漫谈异步编程发展史
70782 9
|
6月前
|
前端开发
promis:异步编程
promis:异步编程
21 0
|
5月前
|
前端开发
异步编程
异步编程
269 0
|
9月前
|
C#
C#异步编程
C#异步编程
164 0
|
10月前
|
消息中间件 Java 数据库
实现异步编程的方式
实现异步编程的方式
|
11月前
|
C#
c#异步编程
c#异步编程原理,await asnyc的使用方法。异步编程是指在程序执行过程中,不需要等待某个操作完成,就可以继续执行后续的代码。
267 0
|
存储 算法 前端开发
一文了解异步编程基础
异步编程是指并发编程的范式,其中除了单个主应用程序线程之外,工作可以委托给一个或多个并行工作线程。这被称为非阻塞系统,其中整体系统速度不受订单执行的影响,并且多个进程可以同时发生。
|
前端开发 JavaScript Java
Promise: 异步编程的理解和使用
Promise 最早出现在 1988 年,由 Barbara Liskov、Liuba Shrira 首创(论文:Promises: Linguistic Support for Efficient Asynchronous Procedure Calls in Distributed Systems)。并且在语言 MultiLisp 和 Concurrent Prolog 中已经有了类似的实现。
199 0
|
前端开发 Java 编译器
异步编程的几种方式,你知道几种?
近期尝试在搬砖专用语言 Java 上实现异步,起因和过程就不再详述了,总而言之,心中一万头草泥马奔过。但这个过程也没有白白浪费,趁机回顾了一下各种异步
异步编程的几种方式,你知道几种?
|
C# 编译器 数据库
C#并发编程之异步编程(二)
C#并发编程之异步编程(二)写在前面前面一篇文章介绍了异步编程的基本内容,同时也简要说明了async和await的一些用法。本篇文章将对async和await这两个关键字进行深入探讨,研究其中的运行机制,实现编码效率与运行效率的提升。
1387 0