欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-11 16:56:28
一、涉及内容 async & await是C# 5.0引入的,控制台输出所使用的$符号(拼接字符串)是C# 6.0引入的,其功能类似于string.Format()方法。 二、多线程、异步、同步之间的联系与区别 厨房案例: 比如说你要炒5道菜ABCDE,但是只有两个炉子可以用,即同时只能炒两道菜。在 ......

    一、涉及内容

    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。");
        }
    }

    运行结果如下:

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

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

    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。");
        }
    }

    运行结果如下:

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

    三、async & await 结构

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

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

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

    3)await表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个await表达式(不存在 await 表达式的话ide会发出警告)。

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

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

    四、异步方法

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

    语法分析:

    1)关键字:方法头使用async修饰符。
    2)要求:需有await表达式(可多个)方可进行异步操作,否则视为普通方法进行同步操作。
    3)返回类型:只能返回3种类型(void、task和task<t>)。task和task<t>标识返回的对象会在将来完成工作,表示调用方法和异步方法可以继续执行。
    4)参数:数量不限,但不能使用out和ref关键字。
    5)命名约定:方法后缀名应以async结尾。
C#线程学习笔记八:async & await入门

    参考自: