自从C#5.0增长异步编程以后,异步编程愈来愈简单,async和await用的地方愈来愈多,愈来愈好用,只要用异步的地方都是一连串的异步,若是想要异步编程的时候,须要从底层开始编写,这样后边使用的时候就是异步,那么底层是如何实现??咱们如何编写高效率的异步方法??html
基于任务的异步编程模型 (TAP) 提供了异步代码的抽象化,你只需像往常同样将代码编写为一连串语句便可,在开始调用的地方运行。例如:var task = method()①; await task②; 在①的时候开始运行可能尚未运行完,在②程序挂起等待运行完,中间怎么运行的你不须要知道,编译器会作若干操做的。当开启多个任务的时候,像要他们都执行完,在执行其余的时候,能够await Task.WhenAll(task1,task2 .....);编程
await 运算符应用于异步方法,在方法的执行中插入挂起点,直到所等待任务完成。使用async 和await定义异步方法不必定会建立新线程,当编译器看到await关键字时,线程会挂起等待运行结束。
await 仅可用于由 async 关键字修改的异步方法中,使用 async 修饰符定义的方法一般包含一个或多个 await 表达式,使用await运算符的任务一般是实现[基于任务的异步模式(TAP)]的方法调用返回,返回值包括 Task、Task<TResult>、ValueTask 和 ValueTask<TResult> 对象的方法。多线程
1. 调用 Wait() 或 Result 的代码位于 UI 线程。
2. Task 的实际执行在其余线程,且须要返回 UI 线程。
死锁的缘由:UWP、WPF、Windows Forms 程序的 UI 线程都是单线程的。为了不产生死锁,你应该一条道走到黑, Async All the Way。或者.ConfigureAwait(false)异步
7.0为async新增的ValueTask的做用(若是没有在Nuget上下载System.Threading.Tasks.Extensions,ValueTask就在这个库中),ValueTask用于值类型的异步;Task为引用类型的,每次须要分配空间。
例如:async
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会更好。优化
[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,原来又是编译器提供的语法糖。ui
[__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会不会建立一个线程,这却是不必定,这个由线程池决定,那么异步了不建立一个线程,怎么异步的,这里的异步多是运行在已经有的线程上。spa
1. C#中await/async闲说线程
2. .NET中并行开发优化
3. C# Task.Run 和 Task.Factory.StartNew 区别
4. C#中多线程的并行处理
5. C#中多线程中变量研究