• C#线程学习笔记八:async & await入门一


        一、涉及内容

        async & await是C# 5.0引入的,控制台输出所使用的$符号(拼接字符串)是C# 6.0引入的,其功能类似于string.Format()方法。

        二、多线程、异步、同步之间的联系与区别

        厨房案例:

        比如说你要炒5道菜ABCDE,但是只有两个炉子可以用,即同时只能炒两道菜。在这里,炉子就是线程。

        假如两个炉子分别同时炒A和B,那剩下的CDE只能等A或B炒完了才能开始。这个等待的过程就是同步,我们称之为阻塞,即这个时候你只能炒A和B这两道菜。

        假如你还有一台咖啡机,在你炒A和B的时候顺手把咖啡豆和水放到咖啡机里打开开关,然后你就不用管它了。此时,就是新开了一个线程去煮咖啡,而煮咖啡

    是由咖啡机自动完成的并不影响继续炒菜,所以煮咖啡这个线程是异步的,我们称之为非阻塞

        当咖啡机叮的一声通知你咖啡已经煮好了,你要去把咖啡拿出来加点糖或奶什么的,这个拿咖啡的动作我们称之为回调,这个是咖啡机线程完成之后通知你要去

    做的动作。

        简单来说:

        会占用你的时间让你无法去做其它事情的任务叫做同步任务(炒菜要专注否则会糊锅)。

        那些不需要占用你的时间的任务叫做异步任务(咖啡机自己会把咖啡煮好,不需要你一直看着它)。

        下面代码演示不使用异步的情况:

        class Program
        {
            //创建计时器
            private static readonly Stopwatch stopwatch = new Stopwatch();
    
            static void Main(string[] args)
            {
                #region async & await入门一之不使用异步
                //启动计时器
                stopwatch.Start();
                //URL地址
                const string url1 = "http://www.cnblogs.com/";
                const string url2 = "http://www.cnblogs.com/atomy/";
                //异步下载某网站内容,并统计字符的个数。
                var result1 = CountCharacters("url1", url1);
                var result2 = CountCharacters("url2", url2);
                //主要是通过拼接字符串达到耗时操作
                for (var i = 0; i < 3; i++)
                {
                    ExtraOperation(i + 1);
                }
                //控制台输出
                Console.WriteLine($"{url1} 的字符个数:{result1}");
                Console.WriteLine($"{url2} 的字符个数:{result2}");
                Console.WriteLine($"总耗时{stopwatch.ElapsedMilliseconds}ms。");
                Console.Read();
                #endregion
            }
    
            /// <summary>
            /// 统计字符个数
            /// </summary>
            /// <param name="id"></param>
            /// <param name="address"></param>
            /// <returns></returns>
            private static int CountCharacters(string name, string address)
            {
                var wc = new WebClient();
                Console.WriteLine($"{name}开始调用,历时{stopwatch.ElapsedMilliseconds}ms,线程id={Thread.CurrentThread.ManagedThreadId}。");
    
                var result = wc.DownloadString(address);
                Console.WriteLine($"{name}调用完成,历时{stopwatch.ElapsedMilliseconds}ms,线程id={Thread.CurrentThread.ManagedThreadId}。");
    
                return result.Length;
            }
    
            /// <summary>
            /// 额外操作
            /// </summary>
            /// <param name="id"></param>
            private static void ExtraOperation(int id)
            {
                //这里是通过拼接字符串进行一些相对耗时的操作
                var s = "";
                for (var i = 0; i < 6000; i++)
                {
                    s += i;
                }
                Console.WriteLine($"第{id}次ExtraOperation执行完成,历时:{stopwatch.ElapsedMilliseconds}ms。");
            }
        }
    View Code

        运行结果如下:

        下面代码演示使用异步的情况:

        class Program
        {
            //创建计时器
            private static readonly Stopwatch stopwatch = new Stopwatch();
    
            static void Main(string[] args)
            {
                #region async & await入门一之使用异步
                //启动计时器
                stopwatch.Start();
                //URL地址
                const string url1 = "http://www.cnblogs.com/";
                const string url2 = "http://www.cnblogs.com/atomy/";
                //异步下载某网站内容,并统计字符的个数。
                Task<int> t1 = CountCharactersAsync("url1", url1);
                Task<int> t2 = CountCharactersAsync("url2", url2);
                //主要是通过拼接字符串达到耗时操作
                for (var i = 0; i < 3; i++)
                {
                    ExtraOperation(i + 1);
                }
                //控制台输出
                Console.WriteLine($"{url1} 的字符个数:{t1.Result}");
                Console.WriteLine($"{url2} 的字符个数:{t2.Result}");
                Console.WriteLine($"总耗时{stopwatch.ElapsedMilliseconds}ms。");
                Console.Read();
                #endregion
            }
    
            /// <summary>
            /// 统计字符个数
            /// </summary>
            /// <param name="id"></param>
            /// <param name="address"></param>
            /// <returns></returns>
            private static async Task<int> CountCharactersAsync(string name, string address)
            {
                var wc = new WebClient();
                Console.WriteLine($"{name}开始调用,历时{stopwatch.ElapsedMilliseconds}ms,线程id={Thread.CurrentThread.ManagedThreadId}。");
    
                var result =await wc.DownloadStringTaskAsync(address);
                Console.WriteLine($"{name}调用完成,历时{stopwatch.ElapsedMilliseconds}ms,线程id={Thread.CurrentThread.ManagedThreadId}。");
    
                return result.Length;
            }
    
            /// <summary>
            /// 额外操作
            /// </summary>
            /// <param name="id"></param>
            private static void ExtraOperation(int id)
            {
                //这里是通过拼接字符串进行一些相对耗时的操作
                var s = "";
                for (var i = 0; i < 6000; i++)
                {
                    s += i;
                }
                Console.WriteLine($"第{id}次ExtraOperation执行完成,历时:{stopwatch.ElapsedMilliseconds}ms。");
            }
        }
    View Code

        运行结果如下:

        三、async & await 结构

        async & await结构可分成三部分:

        1)调用方法:该方法调用异步方法,然后在异步方法执行其任务的时候继续执行。

        2)异步方法:该方法异步执行工作,然后立刻返回到调用方法。

        3)await表达式:用于异步方法内部,指出需要异步执行的任务。

        四、异步方法

        异步方法:在执行完成前立即返回调用方法,在调用方法继续执行的过程中完成任务。

        语法分析:

        1)关键字:方法头返回类型前使用async关键字,它是一个上下文关键字。
        2)要求:需有await表达式(可多个)方可进行异步操作,否则视为普通方法进行同步操作。
        3)返回类型:只能返回3种类型(void、Task和Task<T>)。Task和Task<T>标识返回的对象会在将来完成工作,表示调用方法和异步方法可以继续执行。
        4)参数:数量不限,但不能使用out和ref关键字。
        5)命名约定:方法后缀名应以Async结尾。
        6)其它:匿名方法和 Lambda 表达式也可以作为异步对象。

        参考自:

        https://www.cnblogs.com/woxihuadabai/p/8042652.html

        https://www.cnblogs.com/liqingwen/p/5831951.html

  • 相关阅读:
    C语言编程题
    boost-使用说明
    CButton控件
    sprintf()与sscanf()
    MFC中的几个虚函数
    CProgressCtrl进度条控件实现进度滚动效果
    移动窗口和根据条件查找指定窗口
    VC播放mp3的方法
    CEdit控件[转]
    关于鼠标的一些操作
  • 原文地址:https://www.cnblogs.com/atomy/p/12038318.html
Copyright © 2020-2023  润新知