.NETCore——异步

本文章是我听B站杨中科的所做的笔记

杨中科B站视频链接:.NET 6教程,.Net Core 2022视频教程,杨中科主讲_哔哩哔哩_bilibili

生活的例子:

同步点餐:一个服务员来记菜

异步点餐:服务员给菜单客户点餐

异步点餐不会提升单个客户点餐的速度

web服务器能够同时服务的请求数量有限

async、await不等于“多线程”

异步原理

对于不支持的异步方法怎么办?wait()(无返回值);Result(有返回值)。风险:死锁。尽管不用

await、async是语法糖,最终编译成“状态机调用”

async的方法会被C#编译器编译成一个类,会主要根据await调用进行切分为多个状态,对async方法的调用会被拆分为对MoveNext的调用

用await看似是“等待”,经过编译后,其实没有“wait”

async背后线程切换

为什么要把一个async方法拆分为多个状态然后分为多次调用?异步的可以避免线程等待耗时操作,但是await还是等待呀?

await调用的等待期间,.net会把当前的线程返回给线程池,等异步方法调用执行完毕后,框架会从线程池再取出来一个线程执行后续的代码

Thread.CurrentThread.ManagedThreadId获取当前线程Id。验证:在耗时异步(写入大字符串)操作前后分别打印线程Id。如果写入内容少,会发现线程Id不变,这是因为微软做的优化:到要等待的时候,如果发现已经执行结束了,那就没必要再切换线程了,剩下的代码就继续在之前的线程上继续执行了

异步方法不等于多线程

异步方法的代码并不会自动在新线程中执行,除非把代码放到新线程中执行

把要执行的代码以委托的形式传递给Task.Run(),这样就会从线程池中取出一个线程执行我们的委托await Task.Run(()=>{//耗时操作代码,可以return返回值})

为什么有的异步方法没标注async

async方法缺点:

1、异步方法会生成一个类,运行效率没有普通方法高

2、可能会占用非常多的线程

没有用async的好处:只甩手Task,不“拆完了再装”反编译上面的代码只是普通的方法调用,优点:运行效率更高,不会造成线程浪费

返回值为Task的不一定都标注async,标注async只是让我们可以更方便的await而已

如果一个异步方法只是对别的异步方法调用的转发,并没有太多复杂的逻辑(比如等待A的结果,在调用B;把A调用的返回值拿到内部做一些处理再返回),那么就可以去掉async关键字

不要用sleep()

如果想在异步方法中暂停一段时间,不要用Thread.Sleep(),因为它会阻塞调用线程,而要用await Task.Delay()。在控制台中没看到区别,但是放到winform程序中就能看到区别了。asp.net core中也看不到区别但是sleep()会降低并发,用点餐举例子

CancellationToken

场景:有时需要提前终止任务,比如:请求超时、用户取消请求

很多异步方法都有CancellationToken参数,用于获得提前终止执行的信号

CancellationToken结构体:None:空 bool IsCancellationRequested是否取消 Register(Action callback)注册取消监听 ThrowifCancellationRequested()如果任务被取消,执行到这句话就抛异常

CancellationTokenSource: CancelAfter()超时后发出取消信号 Cancel()发出取消信号 CancellationToken Token

asp.net core开发中,一般不需要自己处理CancellationToken、CancellationTokenSourse这些,只要做到“能转发CancellationToken就转发”即可。asp.net core会对于用户请求中断进行处理

异步的WhenAll

Task类的重要方法:

1、Task WhenAny(IEnumerable tasks)等,任何一个Task完成,Task就完成

2、Task WhenAll(params Task[] tasks)等,所有Task完成,Task才完成。用于等待多个任务执行结束,但是不在乎它们的执行顺序

3、FromResult()创建普通数值的Task对象

异步其他问题

async是提示编译器为异步方法中的await代码进行分段处理的,而一个异步方法是否修饰了async对于方法的调用者来讲没区别,因此对于接口中的方法或者抽象方法不能修饰为async

异步与yield:复习:yield return不仅能都简化数据的返回,而且可以让数据处理“流水线化”,提升性能

在旧版C#中,async方法中不能用yield。从C#8.0开始,把返回值声明为IAsyncEnumerable(不要带Task),然后遍历的时候用await foreach()即可。

static async Task Main(string[] args)
{
    await foreach(var s in Test())
    {
        Console.WriteLine(s);
    }
}
static async IAsyncEnumerable Test()
{
    yield return "hello";
    yield return "yzk";
    yield return "youzack";
}

网上文章写的

同步:请求进来时服务器会分配一个线程处理该请求,该线程在处理请求时一直处于繁忙状态,并且不能处理其他的请求 异步:请求进来时服务器会分配一个线程处理该请求,该线程在处理请求的同时,可以处理其他的请求

用async/away目的是简化异步编程模式 异步:async/away 如果执行到away时,它会立即返回并且释放该线程,余下的代码会放进一个回调中,耗时操作完成时才会回调执行 同步:就是线程一直占用,直到程序执行完成

异步:线程同一时间可以处理多个请求,防止请求队列和线程池的增长 同步:线程同一时间只能处理一个请求

总结,异步不能提升响应速度,但是可以提升响应能力(吞吐量)

.NET Web应用中为什么要使用async/await异步编程? - 知乎

你可能感兴趣的:(.netcore,c#)