一、介绍
1、控制台测试await/async
2、C# 5.0 .Net framework4.5 CLR4.0 以后才有,本身是一种语法糖
二、基本测试
1、不加await测试。
private async static Task TestAsync() {Log.Info($"当前主线程id={Thread.CurrentThread.ManagedThreadId}");NoReturnNoAwait();for (int i = 0; i < 10; i++){Thread.Sleep(300);Log.Info($"Main Thread Task ManagedThreadID = {Thread.CurrentThread.ManagedThreadId}");}}private static async void NoReturnNoAwait() {Log.Info($"NoReturn Sleep before await,ThreadID={Thread.CurrentThread.ManagedThreadId}");TaskFactory taskFactory = new TaskFactory();Task task = taskFactory.StartNew(() =>{Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(3000);Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");});Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");}
2、加await测试。
private async static Task TestAsync() {Log.Info($"当前主线程id={Thread.CurrentThread.ManagedThreadId}");NoReturn();//NoReturnNoAwait();for (int i = 0; i < 10; i++){Thread.Sleep(300);Log.Info($"Main Thread Task ManagedThreadID = {Thread.CurrentThread.ManagedThreadId}");}}private static async void NoReturn() {Log.Info($"NoReturn Sleep before await,ThreadID={Thread.CurrentThread.ManagedThreadId}");TaskFactory taskFactory = new TaskFactory();Task task = taskFactory.StartNew(() => {Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(3000);Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");});await task; //主线程到这里就返回了,执行主线程任务Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");}
结果:从打印出来的两种执行顺序来看,加了await以后,主线程运行到await这行就会执行
回主线程任务。而await后面的代码将由主线程或其他线程来执行原理:await后面的代码,会被封装成委托,在await task之后成为回调(编译器功能,状态机实现) ,这个回调的线程是不确定的,可能是主线程,可能是子线程也可能是其他线程。
它可以等价于task.ContinueWith(t=>{}) 这里包起来
验证一下:
private async void AwaitTest() {//方法一:NoReturn();//方法二:TaskFactory taskFactory = new TaskFactory();Task task = taskFactory.StartNew(() =>{Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(3000);Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");});task.ContinueWith(t =>{callBack();});await task;}private static async void NoReturnNoAwait(){Log.Info($"NoReturn Sleep before await,ThreadID={Thread.CurrentThread.ManagedThreadId}");TaskFactory taskFactory = new TaskFactory();Task task = taskFactory.StartNew(() =>{Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(3000);Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");});Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");}private void callBack(){Log.Info($"我是一个回调。。");Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");}
三、返回值问题
1、不需要传值的时候,我们返回值就写成Task或者void都可以
2、需要传值的话 ,可以使用这种带泛型传值
四、小案例
private void MainThread() {Log.Info("主线程Start");Async();Log.Info($"aaa {Thread.CurrentThread.ManagedThreadId.ToString("00")}");}private async void Async(){Log.Info($"ddd {Thread.CurrentThread.ManagedThreadId.ToString("00")}");await Task.Run(() =>{Thread.Sleep(500);Log.Info($"bbb {Thread.CurrentThread.ManagedThreadId.ToString("00")}");});Log.Info($"ccc {Thread.CurrentThread.ManagedThreadId.ToString("00")}");}
猜测执行顺序:
1、打印主线程Start
2、主线程进入Async方法,打印ddd
3、碰到了await,主线程返回回去执行,打印aaa
4、子线程等待500毫秒后,并行打印bbb
5、最后回调打印ccc
公布结果: