C#异步简介

xiaoxiao2025-08-28  9

 涉及 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 必须在返回类型前。

 

异步方法简单结构图

转载请注明原文地址: https://www.6miu.com/read-5035364.html

最新回复(0)