先上一段代码,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
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路


















