C#中await/async闲说

原文:C#中await/async闲说

自从C#5.0增加异步编程之后,异步编程越来越简单,async和await用的地方越来越多,越来越好用,只要用异步的地方都是一连串的异步,如果想要异步编程的时候,需要从底层开始编写,这样后边使用的时候就是异步,那么底层是如何实现??我们如何编写高效率的异步方法??

#了解基于任务的异步模式(TAP)

基于任务的异步编程模型 (TAP) 提供了异步代码的抽象化,你只需像往常一样将代码编写为一连串语句即可,在开始调用的地方运行。例如:var task = method()①; await task②; 在①的时候开始运行可能还没有运行完,在②程序挂起等待运行完,中间怎么运行的你不需要知道,编译器会做若干操作的。当开启多个任务的时候,像要他们都执行完,在执行其他的时候,可以await Task.WhenAll(task1,task2 .....);

#了解async/await

await 运算符应用于异步方法,在方法的执行中插入挂起点,直到所等待任务完成。使用async 和await定义异步方法不一定会创建新线程,当编译器看到await关键字时,线程会挂起等待运行结束。
await 仅可用于由 async 关键字修改的异步方法中,使用 async 修饰符定义的方法通常包含一个或多个 await 表达式,使用await运算符的任务通常是实现[基于任务的异步模式(TAP)]的方法调用返回,返回值包括 Task、Task<TResult>、ValueTask 和 ValueTask<TResult> 对象的方法。

# 调用 Task.Wait() 或者 Task.Result 立刻产生死锁的充分条件

1. 调用 Wait() 或 Result 的代码位于 UI 线程。
2. Task 的实际执行在其他线程,且需要返回 UI 线程。
死锁的原因:UWP、WPF、Windows Forms 程序的 UI 线程都是单线程的。为了避免产生死锁,你应该一条道走到黑, Async All the Way。或者.ConfigureAwait(false)

# ValueTask与Task的区别

7.0为async新增的ValueTask的作用(如果没有在Nuget上下载System.Threading.Tasks.Extensions,ValueTask就在这个库中),ValueTask用于值类型的异步;Task为引用类型的,每次需要分配空间。
例如:

public async Task<int> CalculateSum(int a, int b) {
    if (a == 0 && b == 0)
    {
        return 0;
    }

    return await Task.Run(() => a + b);
}

当a,b=0的时候不会运行到task里,这个时候返回task就造成了资源的浪费,修改为以下会效率更高

public async ValueTask<int> CalculateSum2(int a, int b)
{
    if (a == 0 && b == 0)
    {
        return 0;
    }

    return await Task.Run(() => a + b);
}

但是也不是说到处用ValueTask会好,当是引用类型的时候,用ValueTask,你需要关注更多的数据,这个时候用Task会更好。

# await/async原理分析

[AsyncStateMachine(typeof(Class1.<CalculateSum2>d__1))]
public ValueTask<int> CalculateSum2(int a, int b)
{
    Class1.<CalculateSum2>d__1 <CalculateSum2>d__;
    <CalculateSum2>d__.a = a;
    <CalculateSum2>d__.b = b;
    <CalculateSum2>d__.<>t__builder = AsyncValueTaskMethodBuilder<int>.Create();
    <CalculateSum2>d__.<>1__state = -1;
    AsyncValueTaskMethodBuilder<int> <>t__builder = <CalculateSum2>d__.<>t__builder;
    <>t__builder.Start<Class1.<CalculateSum2>d__1>(ref <CalculateSum2>d__);
    return <CalculateSum2>d__.<>t__builder.Task;
}

对CalculateSum2代码解析,发现没有await/async,原来又是编译器提供的语法糖。

[__DynamicallyInvokable, DebuggerStepThrough, SecuritySafeCritical]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
    if (stateMachine == null)
    {
        throw new ArgumentNullException("stateMachine");
    }
    ExecutionContextSwitcher executionContextSwitcher = default(ExecutionContextSwitcher);
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
        ExecutionContext.EstablishCopyOnWriteScope(ref executionContextSwitcher);
        stateMachine.MoveNext();
    }
    finally
    {
        executionContextSwitcher.Undo();
    }
}

对Start方法进行分析,可以看出MoveNext,程序的运行其实还是一步一步进行的,那么await/async会不会创建一个线程,这倒是不一定,这个由线程池决定,那么异步了不创建一个线程,怎么异步的,这里的异步可能是运行在已经有的线程上。

.NET中并行开发优化C#中多线程并行处理C#中多线程变量的研究这几片文章都是介绍C#中多线程的,介绍的侧重点不同。

原文地址:https://www.cnblogs.com/lonelyxmas/p/11100203.html

时间: 2024-10-04 20:12:08

C#中await/async闲说的相关文章

[译] C# 5.0 中的 Async 和 Await (整理中...)

C# 5.0 中的 Async 和 Await [博主]反骨仔 [本文]http://www.cnblogs.com/liqingwen/p/6069062.html 伴随着 .NET 4.5 和 Visual Studio 2012 的 C# 5.0 ,我们可以使用的新的异步模式,这里涉及到 async 和 await 关键字.有许多不同点的观点,比起之前我们所看到的代码,它的可读性和实用性是否更加突出.我们将通过一个例子,看看它与当前的做法有何“与众不同”. 线性代码与非线性代码 大部分的软

promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解

* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的通知机制. 异步:当事情处理完成后被请求者会发信息通知请求者该事情处理完成.在这期间被请求者可以选择是继续等待命令请求完成还是去做其他事等待被请求者返回. 同步:当事情处理完成后被请求者不会告知请求者,等到请求者发来询问是才会告知 阻塞:非阻塞 指的是请求者 阻塞:针对请求者来说的,委托其他人处理一

[C#] .NET4.0中使用4.5中的 async/await 功能实现异步

在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去,建议直接使用.NET Framework 4.5吧:但是如果已经发布了,又不想用户重新升级框架到.NET Framework 4.5,那也有一个办法,那就是使用库:Microsoft.Bcl.Async 在4.5中使用async/await 的地方如下: 好处呢,我不多说,我想说的是: What

ES7中的async和await

ES7中的async和await 在上一章中,使用Promise将原本的回调方式转换为链式操作,这就将一个个异步执行的操作串在一条同步线上了.下一次的操作必须等待当前操作的结束. 使用Promise的最后,遇到了一个问题,就是如果要对已经获得数据数组进行遍历,并在遍历中继续对每一条数据做异步请求操作,这就构成了一个树状查询. 蠢办法 对于上述问题,我们完全可以用上一章中的垃圾代码来构建一个for循环的嵌套then! 但上一章已经说过,千万不要写出这种垃圾代码,所以如果你的node或者浏览器并不支

.net core 入坑经验 - 1、await async

已经有些日子没学习新知识了,心血来潮想试试core有多大变化和跨平台运行 所以现在就开始捣鼓,然而由于是从.net 4.0直接"跃升"到.net core 以及 asp.net mvc core..发现变化真是太大了. 准备记录一系列的遇到的问题和变化,方便以后出问题快速查阅吧. 首先我要实现一个获取网页HTML的方法,问题来了. 我需要使用HttpWebRequest对象进行获取字符串流,而在获取的过程中发现该类已经不存在以前的GetRequestStream()方法了,而变为了Ge

Silverlight项目笔记1:UI控件与布局、MVVM、数据绑定、await/async、Linq查询、WCF RIA Services、序列化、委托与事件

最近从技术支持转到开发岗,做Silverlight部分的开发,用的Prism+MVVM,框架由同事搭好,目前做的主要是功能实现,用到了一些东西,侧重于如何使用,总结如下:   1.UI控件与布局     2.MVVM     3.数据绑定     4.await/async     5.Linq查询     6.WCF RIA Services     7.序列化     8.委托与事件 1.UI控件与布局 常用的主要是Grid.StackPanel.Border,其中最常用的的是Grid,是一

多线程-Task、await/async

Task创建无返回值 Task是.netframwork3.0重新分装的多线程类.原因以前的多线程(thread threadpool)不好用.(.net framwork也是的发展的,现在的EF,刚开始是一个edmx文件,现在的code first,ef轻量级.但是其他有的技术也是死掉了) Task具有线程执行的可控性,返回值,代码书写简单,性能好等特点. Task创建主要有三种方式 1.Task参数 Task t = new Task(() => { for (int i = 0; i <

5分种让你了解javascript异步编程的前世今生,从onclick到await/async

javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为浏览器设计的GUI编程语言,GUI编程的特性之一是保证UI线程一定不能阻塞,否则体验不佳,甚至界面卡死. 一般安卓开发,会有一个界面线程,一个后台线程,保证界面的流畅.由于javascript是单线程,所以采用异步非阻塞的编程模式,javascript的绝大多数api都是异步api. 本文是本人的一个

MVC 如何在一个同步方法(非async)方法中等待async方法

MVC 如何在一个同步方法(非async)方法中等待async方法 问题 首先,在ASP.NET MVC 环境下对async返回的Task执行Wait()会导致线程死锁.例: public ActionResult Asv2() { //dead lock var task = AssignValue2(); task.Wait(); return Content(_container); } private void Assign() { _container = "Hello World&q