一、介绍
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
公布结果: