C#异步简介

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36981814/article/details/83381607

 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $"" 来拼接字符串,相当于string.Format() 方法。

序言


启动程序之后,系统会在内存中创建一个新的进程。进程是构成运行程序资源的集合。在进程内部,有称为线程的内核对象,它代表的是真正的执行程序。系统会在 Main 方法的第一行语句就开始线程的执行。

    线程:
               ①默认情况,一个进程只包含一个线程,从程序的开始到执行结束;
               ②线程可以派生自其它线程,所以一个进程可以包含不同状态的多个线程,来执行程序的不同部分;
               ③一个进程中的多个线程,将共享该进程的资源;
               ④系统为处理器执行所规划的单元是线程,而非进程。


为什么要使用异步编程


提高程序的性能,相应多端请求或者提高响应速度,采用异步编程。在异步的程序中,代码不需要按照编写是的顺序执行。需要用到5.0引入的 async/await
来构建异步方法。


不用异步和使用异步的比较

未使用异步运行结果

使用异步运行结果

技巧类提示:
直接拼接字符串是一种比较消耗性能的手段,如果对字符串连接有性能要求的话应该使用StringBuilder方法。

代码解释


OldTest.async.await代码:

 private static readonly Stopwatch stopwatch = new Stopwatch();

        static void Main(string[] args)
        {
            stopwatch.Start();

            const string strTest1 = "https://www.csdn.net/";
            const string strTest2 = "https://blog.csdn.net/qq_36981814";

            var strCountResult1 = CountChars(1, strTest1);
            var strCountResult2 = CountChars(2, strTest2);

            for (int i = 0; i < 3; i++)
            {
                ExtraOperation(i + 1);
            }

            Debug.WriteLine($"{strTest1} 的字符个数:{strCountResult1}");
            Debug.WriteLine($"{strTest2} 的字符个数:{strCountResult2}");
        }

        private static void ExtraOperation(int id)
        {
            var s = "";

            for (var i = 0; i < 6000; i++)
            {
                s += i;
            }
            Debug.WriteLine($"id={id}的 ExtraOperation 方法完成:{stopwatch.ElapsedMilliseconds} ms");
        }

        private static int CountChars(int id, string address)
        {
            var wc = new WebClient();
            Debug.WriteLine($"开始调用 id = {id}:{stopwatch.ElapsedMilliseconds} ms");
            var result = wc.DownloadString(address);
            Debug.WriteLine($"调用完成 id = {id}:{stopwatch.ElapsedMilliseconds} ms");
            return result.Length;
        }

NewTest.async.await代码:

   private static readonly Stopwatch stopwatch = new Stopwatch();

        static void Main(string[] args)
        {
            stopwatch.Start();

            const string strTest1 = "https://www.csdn.net/";
            const string strTest2 = "https://blog.csdn.net/qq_36981814";

            Task<int> strCountResult1 = CountCharsAsync(1, strTest1);
            Task<int> strCountResult2 = CountCharsAsync(2, strTest2);

            for (int i = 0; i < 3; i++)
            {
                ExtraOperation(i + 1);
            }

            Debug.WriteLine($"{strTest1} 的字符个数:{strCountResult1.Result}");
            Debug.WriteLine($"{strTest2} 的字符个数:{strCountResult2.Result}");

        }

        private static void ExtraOperation(int id)
        {
            var s = "";

            for (var i = 0; i < 6000; i++)
            {
                s += i;
            }
            Debug.WriteLine($"id={id}的 ExtraOperation 方法完成:{stopwatch.ElapsedMilliseconds} ms");
        }

        private static async Task<int> CountCharsAsync(int id, string address)
        {
            var wc = new WebClient();
            Debug.WriteLine($"开始调用 id = {id}:{stopwatch.ElapsedMilliseconds} ms");
            var result = await wc.DownloadDataTaskAsync(address);
            Debug.WriteLine($"调用完成 id = {id}:{stopwatch.ElapsedMilliseconds} ms");
            return result.Length;
        }

①从 Main 方法执行到 CountCharactersAsync(1, url1) 方法时,该方法会立即返回,然后才会调用它内部的方法开始下载内容。该方法返回的是一个 Task<int> 类型的占位符对象,表示计划进行的工作。这个占位符最终会返回 int 类型的值。
②这样就可以不必等 CountCharactersAsync(1, url1) 方法执行完成就可以继续进行下一步操作。到执行 CountCharactersAsync(2, url2)  方法时,跟 ① 一样返回 Task<int> 对象。
③然后,Main 方法继续执行三次 ExtraOperation 方法,同时两次 CountCharactersAsync 方法依然在持续工作 。
④t1.Result 和 t2.Result 是指从 CountCharactersAsync 方法调用的 Task<int> 对象取结果,如果还没有结果的话,将阻塞,直有结果返回为止。


 asynic/await结构


 同步方法:一个程序调用某个方法,等到其执行完成之后才进行下一步操作。这也是默认的形式。
 异步方法:一个程序调用某个方法,在处理完成之前就返回该方法。通过 async/await 我们就可以实现这种类型的方法。
 async/await 结构可分成三部分:
(1)调用方法:该方法调用异步方法,然后在异步方法执行其任务的时候继续执行;
(2)异步方法:该方法异步执行工作,然后立刻返回到调用方法;
(3)await 表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个 await 表达式(不存在 await 表达式的话 IDE 会发出警告)。

异步方法详解

异步方法:在执行完成前立即返回调用方法,在调用方法继续执行的过程中完成任务。
语法分析:
(1)关键字:方法头使用 async 修饰。
(2)要求:包含 N(N>0) 个 await 表达式(不存在 await 表达式的话 IDE 会发出警告),表示需要异步执行的任务。
(3)返回类型:只能返回 3 种类型(void、Task 和 Task<T>)。Task 和 Task<T> 标识返回的对象会在将来完成工作,表示调用方法和异步方法可以继续执行。
(4)参数:数量不限,但不能使用 out 和 ref 关键字。
(5)命名约定:方法后缀名应以 Async 结尾。
(6)其它:匿名方法和 Lambda 表达式也可以作为异步对象;async 是一个上下文关键字;关键字 async 必须在返回类型前。

异步方法简单结构图

猜你喜欢

转载自blog.csdn.net/qq_36981814/article/details/83381607