使用时注意点
1 private async void button5_Click(object sender, EventArgs e) 2 { 3 /* 4 string i1 = await F1Async(); 5 MessageBox.Show("i1=" + i1); 6 string i2 = await F2Async(); 7 MessageBox.Show("i2=" + i2); 8 */ 9 Task<string> task1 = F1Async(); 10 Task<string> task2 = F2Async(); 11 string i1 = await task1; 12 MessageBox.Show("i1=" + i1); 13 string i2 = await task2; 14 MessageBox.Show("i2=" + i2); 15 } 16 17 static Task<string> F1Async() 18 { 19 MessageBox.Show("F1 Start"); 20 return Task.Run(() => { 21 System.Threading.Thread.Sleep(1000); 22 MessageBox.Show("F1 Run"); 23 return "F1"; 24 }); 25 } 26 27 static Task<string> F2Async() 28 { 29 MessageBox.Show("F2 Start"); 30 return Task.Run(() => { 31 System.Threading.Thread.Sleep(2000); 32 MessageBox.Show("F2 Run"); 33 return "F2"; 34 }); 35 }
如上两个异步方法,在调用时,第一种调用提示框会按步骤弹出,而第二种则混乱的弹出,但这也不难理解因为多线程本来就是分片执行不按代码顺序;
第二种写法的await是作为一个最后的保险作用,它的意义在于如果开始就执行了ok,如果没执行则这步该执行了
不能使用async修饰而要调用异步方法怎么办?
出现这种情况比较少,此时可以获得Task<T>类型的返回值,获取Task<T>.Result()方法,终止异步;
但请注意尽量少的使用Result()方法,他会造成数据上下文的死锁问题。
如果返回值就是一个立即可以随手可得的值,那么就用 Task.FromResult();
异步方法的风格转换
Task.Factory.FromAsync()把 IAsyncResult 转换为 Task,这样 APM 风格的 api 也可以用 await 来调用
await修饰与并发执行的顺序
被await修饰的异步方法,一定会按照顺序执行并结束,所以如果没有顺序要求可以不使用await修饰并发任务
eg
1 private async void button1_Click(object sender, EventArgs e) 2 { 3 HttpClient hc = new HttpClient(); 4 var task1 = hc.GetStringAsync(textBox1.Text); 5 var task2 = hc.GetStringAsync(textBox2.Text); 6 var task3 = hc.GetStringAsync(textBox3.Text); 7 Task.WaitAll(task1, task2, task3); 8 label1.Text = task1.Result.Length.ToString(); 9 label2.Text = task2.Result.Length.ToString(); 10 label3.Text = task3.Result.Length.ToString(); 11 }