C#异步和多线程的理解
1. 异步编程(Asynchronous Programming)
异步编程是通过非阻塞方式执行任务,通常适用于I/O 密集型任务,例如文件读写、网络请求、数据库访问等。这类操作不需要占用大量 CPU 资源,而是等待外部资源(如网络或硬盘)响应。
在 C# 中,异步编程使用 async
和 await
关键字来实现。异步方法会返回 Task
或 Task<T>
,调用 await
后,主线程可以继续执行其他代码,不会被阻塞。异步任务完成后,程序会回到 await
的位置继续执行。
异步代码示例
以下是一个使用异步编程的示例:
using System; using System.Net.Http; using System.Threading.Tasks; class Program { static async Task Main() { Console.WriteLine("Starting download..."); string content = await DownloadContentAsync("https://example.com"); Console.WriteLine("Download completed!"); Console.WriteLine($"Content length: {content.Length}"); } static async Task<string> DownloadContentAsync(string url) { using HttpClient client = new HttpClient(); // 异步地开始下载内容 string content = await client.GetStringAsync(url); return content; } }
在这个例子中,DownloadContentAsync
是一个异步方法。调用 await DownloadContentAsync(...)
后,Main
方法不会被阻塞,它会释放 CPU,等到下载完成后再继续执行。这种非阻塞模式适合 I/O 密集型任务。
这里该怎么理解,为什么不会阻塞,举个实际业务的例子,就是微信支付的接口并不马上返回支付结果,这就是没有阻塞线程,线程继续做其他事情,支付结果通过回调接口通知;那么如果不是异步会是什么样的,那就是一直等待微信支付的接口响应,这个时候线程就被阻塞了。异步可以理解成回调,进一步说.Net程序向操作系统读取文件,访问网络,什么时候读到了文件,什么时候网络有了响应再回调给.Net程序,.Net程序再启用线程池的线程继续完成回调后的任务,这也是异步后线程id会改变的原因。
2. 多线程编程(Multithreading Programming)
多线程编程是通过在多个线程上并行执行任务,适用于CPU 密集型任务,如复杂计算、数据处理等。这类操作需要充分利用 CPU 的多核心能力来同时处理多个任务。
在 C# 中,多线程编程可以通过 Thread
、ThreadPool
、Task
等类实现。与异步不同,多线程会创建多个线程来执行不同的任务,这样多个任务可以并发运行。
多线程代码示例
以下是一个使用多线程的示例:
using System; using System.Threading; using System.Threading.Tasks; class Program { static void Main() { Console.WriteLine("Starting CPU-intensive tasks..."); // 启动两个并行任务 Task task1 = Task.Run(() => PerformCpuIntensiveTask("Task 1")); Task task2 = Task.Run(() => PerformCpuIntensiveTask("Task 2")); // 等待任务完成 Task.WaitAll(task1, task2); Console.WriteLine("All tasks completed."); } static void PerformCpuIntensiveTask(string taskName) { Console.WriteLine($"{taskName} started."); for (int i = 0; i < 1000000000; i++) { // 模拟计算任务 double x = Math.Sqrt(i); } Console.WriteLine($"{taskName} completed."); } }
在这个例子中,Task.Run
会在 ThreadPool
中创建并启动新的线程来执行 PerformCpuIntensiveTask
,这样 Task 1
和 Task 2
就可以并行执行,提高了 CPU 使用效率。
其实无论是时阻塞的耗时还是复杂计算的耗时,这两个都是耗时,但是这两个又有很大区别,阻塞的耗时可以通过回调,释放当前线程来解决阻塞的问题,但是复杂计算的耗时核回调就没有关系了。举个具体点的例子,要计算一个天文级别的数字,一个人要10天,但是你发现这些数子是可以拆开来分给不同的人计算,最后把结果加起来就行了。这种情况下使用多线程处理计算任务,然后把结果加起来,减少了耗时,同时也提高了cpu的使用率。
总结
- 异步主要用于非阻塞 I/O 操作,让程序在等待 I/O 时释放资源,适合 I/O 密集型任务。适用于串行任务,不提升单次耗时,但是对整个程序来说可以提示吞吐量。
- 多线程用于让多个任务并行执行,充分利用 CPU 核心资源,适合 CPU 密集型任务。之前的单次任务可以拆分给不同任务执行的话可以提升耗时,通过消耗硬件资源实现并行或者并发提升效率。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?