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

(0)

相关推荐

  • 一文说通C#中的异步编程

    天天写,不一定就明白. 又及,前两天看了一个关于同步方法中调用异步方法的文章,里面有些概念不太正确,所以整理了这个文章.   一.同步和异步. 先说同步. 同步概念大家都很熟悉.在异步概念出来之前,我 ...

  • C# 异步编程

    基于Task的异步编程模式(TAP)是Microsoft为.Net平台下使用Task进行编程所提供的一组建议,这种模式提供了可以被await消耗(调用)方法的APIs,并且当使用async关键字编写遵 ...

  • 多线程之旅(Thread)

    在上篇文章中我们已经知道了多线程是什么了,那么它到底可以干嘛呢?这里特别声明一个前面的委托没看的同学可以到上上上篇博文查看,因为多线程要经常使用到委托.源码一.异步.同步1.同步(在计算的理解总是要你 ...

  • C#线程学习笔记三:线程池中的I/O线程

    本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/20/MultiThreads.html,记录一下学习过程以备后续查用.     一.I/O线 ...

  • C#线程学习笔记六:线程同步--信号量和互斥体

    本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Mutex_And_Semaphore.html,记录一下学习过程以备后续查用.     ...

  • C#线程学习笔记七:Task详细用法

    一.Task类简介: Task类是在.NET Framework 4.0中提供的新功能,主要用于异步操作的控制.它比Thread和ThreadPool提供了更为强大的功能,并且更方便使用. Task和 ...

  • 【houdini】CG猎人第009期houdini完全基础入门学习笔记-flip流体完全入门II

    --  微资讯 · 微课程  -- 利用零碎时间,走上超神之路! 课程概述 00课程介绍,1从工具架方式创建流体,2手动创建流体模拟,3flip solver全讲解,4融化效果,5密度控制创建流体颜色 ...

  • 【houdini】CG猎人第008期houdini完全基础入门学习笔记-flip流体完全入门I

    --  微资讯 · 微课程  -- 利用零碎时间,走上超神之路! 课程概述 001体素介绍,002houdini中流体模拟方法,003 新旧版本流体节点对比,004houdini12流体参数讲解,00 ...

  • MyBatis-Plus学习笔记(八) 代码自动生成器

    AutoGenerator 是 MyBatis-Plus 的代码生成器 AutoGenerator 可以快速生成 Entity.Mapper.Mapper XML.Service.Controller ...

  • c语言学习笔记(八:struct、union、enum、typedef

    自定义数据类型 1.struct 1)结构体的声明 声明结构体变量:结构体所占内存大小是其成员所占内存之和. struct 结构体类型名{//结构体类型名可省略,匿名结构体 成员表://可以有多个成员 ...

  • 《伤寒论》学习笔记八之表郁轻证。

    最近没顾上更新,今天写一下. 我看了一下上一篇是写到了伤寒兼证.今天继续表郁轻证. 1.太阳病,得之八九日,如疟状,发热恶寒,热多寒少,其人不呕,清便欲自可,一日二三度发.脉微缓者,为欲愈也:脉微而恶 ...

  • IOS学习笔记八(KVO)

    IOS学习笔记八(KVO)