15.1 异步函数简介与思考

 1     public partial class AsyncForm : Form
 2     {
 3         Label label;
 4         Button button;
 5         public AsyncForm()
 6         {
 7             InitializeComponent();
 8             label = new Label { Location = new Point(this.Size.Width / 2, 20), Text = "Length" };
 9             button = new Button { Location = new Point(this.Size.Width / 2, 50), Text = "Click" };
10             button.Click += DisPlayWebSiteLength;
11             AutoSize = true;
12             Controls.Add(label);
13             Controls.Add(button);
14         }
15         async void DisPlayWebSiteLength(object sender, EventArgs e)
16         {
17             label.Text = "Fetching";
18             using (HttpClient client = new HttpClient())
19             {
20                 Task<string> task = client.GetStringAsync("https://www.baidu.com/");
21                 string text = await task;
22                 label.Text = text.Length.ToString();
23             }
24         }
25     }

注意, task 的类型是 Task<string> ,而 await task 表达式的类型是 string 。也就是说,
await 表达式执行的是“拆包”(unwrap)操作,至少在被等待的值为 Task<TResult> 时是这样。
(还可以等待其他类型,但 Task<TResult> 是一个不错的起点。)这是 await 的一个方面,看上
去跟异步编程没什么直接关系,但却让生活更加轻松。
await 的主要目的是在等待耗时操作完成时避免阻塞。它是如何在具体线程中工作的呢?我
们在方法的开始和结束处都设置了 label.Text ,所以可以很自然地认为这两条语句都在UI线程
执行。但显然我们在等待页面下载的时候没有阻塞UI线程。

后续操作 后续操作指在异步操作(或任何 Task )完成时执行的回调程序。在异步方法
中,后续操作保留了方法的控制状态。就像闭包保留了环境中的变量一样,后续操作记
住了它的位置,因此在执行时可回到原处。 Task 类包含一个专门用于添加后续操作的方
法,即 Task.ContinueWith 。

如果在 await 表达式后的代码中加入断点(假设 await 表达式需要后续操作),你会发现堆
栈跟踪中不再拥有 Button.OnClick 方法,该方法早已执行完毕。现在的调用栈是纯粹的
Windows Forms事件循环,在顶部还有一些异步基本结构。如果为了适时地更新UI,而在后台线
程中调用 Control.Invoke ,将得到跟现在非常类似的调用栈,然而现在这些工作已经完全为我
们做好了。起初发现调用栈在眼皮底下发生如此显著的变化时,你可能会有些沮丧,但这对异步
编程来说是绝对必要的。

15.2.2 异步方法

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             PrintPageLength();
 6 
 7             Console.ReadKey();
 8         }
 9 
10         static void PrintPageLength()
11         {
12             Task<int> task = GetPageLengthAsync("https://www.baidu.com/");
13             Console.WriteLine(task.Result);
14         }
15 
16         async static Task<int> GetPageLengthAsync(string url)
17         {
18             using (HttpClient client = new HttpClient())
19             {
20                 Task<string> task = client.GetStringAsync(url);
21                 int lenth = (await task).Length;
22                 return lenth;
23 
24             }
25         }
26     }

猜你喜欢

转载自www.cnblogs.com/kikyoqiang/p/10122614.html