先上一段代码,msdn中举得一个例子,勇哥将其改造了一下,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication16 { class Program { static void Main(string[] args) { var s1= GetUrlContentLengthAsync(); //var s3 = s1.Result; var s3=s1.GetAwaiter().GetResult(); Console.ReadKey(); } public static async Task<int> GetUrlContentLengthAsync() { var client = new HttpClient(); Task<string> getStringTask = client.GetStringAsync("http://www.baidu.com/"); DoIndependentWork(); string contents =await getStringTask; DoIndependentWork2(contents); return contents.Length; } static void DoIndependentWork() { Console.WriteLine("Working..."); } static void DoIndependentWork2(string msg) { Console.WriteLine(msg); } } }
注意这段异步代码的几个特征:
1. 方法签名处的async
2. 返回类型是 Task<int>
注意返回值是int型,而不要理解为Task类型。
3. 方法名以Async结束,这个只是一种约定。
4. 方法体中关键字 await,它至少应该有一个,在该处会暂停函数执行,直到等待异步操作完成方法才能继续。同时,将方法挂起,返回本函数的调用者。
异步编程中最需弄清的是控制流是如何从方法移动到方法的。 下图上对上述代码的执行流程的说明:
图中黑箭头是正常流程(普通的逐条语句运动的流程)
红色箭头是等待时将控制权返回函数调用者
青色箭头恢复函数挂起后继续运行的流程。
由图中我们可以知道:
1,2,3,4,5 是正常的同步运行流程,要注意的是函数client.GetStringAsync它也是个异步的,因此它不是阻塞的。
第6步,也就是await处,函数暂停执行,控制权转回函数的调用者。
第7步,异常方法GetStringAsync执行完毕,取得字符串。这时候程序恢复挂起状态,继续运行第7,8步,函数执行至返回。
因此在上面代码中除了第6步await是异步执行外,其它代码行都是同步执行的。
另外,一个异步方法中,看来一定是调用了另一个异步方法,这样才可以await等待,转移函数控制权给调用者。
这句话是勇哥总结的,不是msdn官方说的。也不知道对不对。请指正。
附录:
异步方法可以具有以下返回类型:
Task(对于执行操作但不返回任何值的异步方法)。
Task<TResult>(对于返回值的异步方法)。
void(对于事件处理程序)。
从 C# 7.0 开始,任何具有可访问的 GetAwaiter 方法的类型。 GetAwaiter 方法返回的对象必须实现 System.Runtime.CompilerServices.ICriticalNotifyCompletion 接口。
从 C# 8.0 开始,IAsyncEnumerable<T> 返回异步流的异步方法 。
附录2:一个简单的winform下的异步小例子
1个按钮,2个textbox,下面这样可以正确异步,窗体也不会死掉,textBox2会先有结果,textBox1再有结果 private async void button1_Click(object sender, EventArgs e) { Does(); textBox2.Text = "1"; } private Task<string> DoWork() { return Task.Run(() => { Thread.Sleep(4000); return "Done with work!"; } ); } private async void Does() { string text = await DoWork(); textBox1.Text = text; } 如果把按钮事件改成下面这样,窗体不会死,但不会异步执行 private async void button1_Click(object sender, EventArgs e) { textBox2.Text =await DoWork(); textBox2.Text = "1"; }
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

