[转]20181110_wait和async的用法
一. Awit和async的由来:
await/async本身是一个语法糖,编译器提供的一个简化编程的功能; 在C#升级和.net Framework升级的时候, 产生的, 所以说并不是CLR的产物
二. 用法:
a) Async出现在方法的声明上, 任何一个方法添加一个async关键字都不会报错
b) 如果只有awit, 是会报错的
c) Awit必须放在task前面, 必须和async成对出现
d) Awit和async成对出现, 会被编译成状态机
三. 一个简单的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | private static async void NoReturn() { //主线程执行 Console.WriteLine($ "NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); TaskFactory taskFactory = new TaskFactory(); //主线程启动一个子线程执行 Task task = taskFactory.StartNew(() => { Console.WriteLine($ "NoReturn Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); Thread.Sleep(3000); Console.WriteLine($ "NoReturn Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); }); await task; //主线程碰到await就返回去执行主线程的其它任务(循环), 而这个方法的下面的代码则不再执行, 等待主线程把其它任务执行完毕, 程序会再次跳回来执行这个方法的下面的其它代码; 但是注意, 再次跳回来的时候, 并不一定是主线程执行, 也有可能是新开一个线程来执行 //这个回调的线程是不确定的:可能是主线程 可能是子线程 也可能是其他线程 Console.WriteLine($ "NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); } //调用代码: NoReturn(); for ( int i = 0; i < 10; i++) { Thread.Sleep(300); Console.WriteLine($ "Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId} i={i}" ); } |
四. Await和async的返回值
a) 当使用await和async时, 如果没有返回值, 则应该标明使用Task作为返回值, 下面的代码演示没有返回值的await和async:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private static async Task NoReturnTask() { //这里还是主线程的id Console.WriteLine($ "NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); Task task = Task.Run(() => { Console.WriteLine($ "NoReturnTask Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); Thread.Sleep(3000); Console.WriteLine($ "NoReturnTask Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); }); await task; Console.WriteLine($ "NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}" ); } |
b) 当使用await和async时, 如果有返回值, 则应该和Task组成泛型来返回: Task<typeName>, 下面的代码演示有返回值的await和async
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private static async Task< long > SumAsync() { Console.WriteLine($ "SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); long result = 0; //1. 先启动一个线程, 主线程遇到这里之后, 就会返回去了, 这个子线程开始执行 await Task.Run(() => { for ( long i = 0; i < 999999999; i++) { result += i; } }); return result; } |
c) Awati和async返回值的使用:
1 2 3 4 | Task< long > t = SumAsync(); Console.WriteLine($ "Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); long lResult = t.Result; //当需要访问result时, 则当前线程必须等待t线程的完成 t.Wait(); //等价于上一行 |
五. 利用await和async像写同步代码一样编写异步执行的代码, 调用方法和第四步的c相同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /// <summary> /// 带返回值的Task /// 要使用返回值就一定要等子线程计算完毕 /// </summary> /// <returns>async 就只返回long</returns> private static async Task< long > SumAsync() { //在await 和 async 中, 先启动一个线程, 执行完成之后, 接着可以继续awit //有点类似同步的方式编程, 但是却是异步执行 Console.WriteLine($ "SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); long result = 0; //1. 先启动一个线程, 主线程遇到这里之后, 就会返回去了, 这个子线程开始执行 await Task.Run(() => { for ( int k = 0; k < 10; k++) { Console.WriteLine($ "SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); Thread.Sleep(1000); } for ( long i = 0; i < 999999999; i++) { result += i; } }); //2. 上面的线程执行完成之后, 输出下面这句话; 可以看做这里是其它的动作 Console.WriteLine($ "SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); //3. 然后继续执行下面这里的线程, 这里又有一个await, 然后主线程又返回去执行其他的 await Task.Run(() => { for ( int k = 0; k < 10; k++) { Console.WriteLine($ "SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); Thread.Sleep(1000); } for ( long i = 0; i < 999999999; i++) { result += i; } }); //4. 这个线程执行完成之后, 开始执行这里输出 Console.WriteLine($ "SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); //5. 碰到await之后, 开了一个子线程, 然后又返回去了 await Task.Run(() => { for ( int k = 0; k < 10; k++) { Console.WriteLine($ "SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); Thread.Sleep(1000); } for ( long i = 0; i < 999999999; i++) { result += i; } }); Console.WriteLine($ "SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}" ); return result; } |
六. 总结:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 1 使用async和await , 能够像写同步代码的方式一样, 达到异步执行的功能 // 2 如果 awit / async 没有返回值, 则使用Task来替代(虽然允许写成void, 但是不要那样做);无返回值时 async Task == async void // 3 如果有返回值则使用Task<类型> 来处理 // 4 await只能出现在Task前面 // 5 不能单独await // 6 await 只能放在task前面 // 7 不管你的await和async标识的方法需不需要返回值, 都不推荐void返回, 应该使用Task来代替, 像第二条所说那样, 因为返回Task和Task<T>则能够使用await, 并且可以和Task.WhenAny, Task.WhenAll等方式组合使用, 但是如果返回Void 不行, 则这条线程链就断了 // 8 如果 awit / async 没有返回值, 则使用Task来替代, 如果有返回值则使用Task<类型>来处理 |
转自https://www.cnblogs.com/wxylog/p/9940916.html