MSDN中关于async/await异步编程的说明

先上一段代码,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,它至少应该有一个,在该处会暂停函数执行,直到等待异步操作完成方法才能继续。同时,将方法挂起,返回本函数的调用者。


异步编程中最需弄清的是控制流是如何从方法移动到方法的。 下图上对上述代码的执行流程的说明:


图中黑箭头是正常流程(普通的逐条语句运动的流程)

红色箭头是等待时将控制权返回函数调用者

青色箭头恢复函数挂起后继续运行的流程。

image.png


由图中我们可以知道:

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

版权声明:本文为博主原创文章,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864