【C#进阶】多线程和异步编程_2024-06-22
关于多线程和异步编程简单来说,就是多线程并行执行任务提速,异步编程等待不浪费资源,并发集合确保数据访问安全,三者合力提升程序效率与反应能力。
1. 理解线程
想象一下,你在厨房做饭,同时需要洗菜、切菜、炒菜。如果你一个人来做,就需要在这些任务之间来回切换,这很慢。但如果请几个朋友帮忙,每人负责一项任务,大家同时工作,效率就高多了。这里的“朋友”就像是计算机中的“线程”。
线程就是计算机程序中执行任务的最小单位。一个程序默认启动时只有一个主线程,但可以通过创建额外的线程来同时执行多个任务,这就是多线程。
示例代码:
using System;
using System.Threading;
class MultiThreadingDemo
{
static void Main()
{
// 这是主线程
Console.WriteLine("主线程开始");
// 创建并启动一个新的线程
Thread thread = new Thread(DoWork);
thread.Start();
Console.WriteLine("主线程继续做其他事情");
// 等待新线程完成(非必须,这里为了演示)
thread.Join();
Console.WriteLine("所有任务完成,主线程结束");
}
static void DoWork()
{
Console.WriteLine("新线程开始执行任务");
Thread.Sleep(2000); // 模拟耗时操作
Console.WriteLine("新线程任务完成");
}
}
注释说明:这段代码中,Main
方法所在的线程是主线程,它创建了一个新线程DoWork
去执行一个耗时任务。Thread.Sleep(2000)
模拟了这个耗时操作,让新线程暂停2秒,期间主线程可以继续执行其他任务。
2. Task和异步编程模型(async和await)
有时候,我们不希望直接管理线程,而是希望程序自动为我们处理并发问题。这时候,就可以使用.NET
提供的Task
和async/await
关键字。
想象你在等待外卖,你可以选择一直站在门口等(阻塞),也可以继续做其他事,听到门铃响再去拿(异步)。async/await
就是让你的程序在等待某些耗时操作(如网络请求)时,可以去做别的事,不浪费时间。
示例代码:
using System;
using System.Threading.Tasks;
class AsyncDemo
{
static async Task Main()
{
Console.WriteLine("开始下载文件");
// 异步下载文件,不会阻塞主线程
await DownloadFileAsync();
Console.WriteLine("文件下载完成");
}
static async Task DownloadFileAsync()
{
// 模拟文件下载耗时操作
await Task.Delay(2000);
Console.WriteLine("文件下载中...");
}
}
注释说明:DownloadFileAsync
方法模拟了文件下载,使用Task.Delay(2000)
模拟耗时操作。await
关键字让调用它的方法(这里是Main
方法)在等待时可以“放手”,去做其他事情,直到DownloadFileAsync
完成才继续往下执行。
3. 并发集合和线程安全
当你在多线程环境下访问和修改共享数据时,可能会遇到数据不一致的问题,这叫做“竞态条件”。为了解决这个问题,.NET
提供了线程安全的集合,比如ConcurrentDictionary
。
想象你和朋友同时编辑一份购物清单,如果不小心同时添加了同样的物品,就会出错。线程安全的集合就像每个人都有自己的笔,在写之前先确认没人同时写,保证清单的正确性。
示例代码:
using System.Collections.Concurrent;
using System.Threading.Tasks;
class ThreadSafeCollectionsDemo
{
static ConcurrentDictionary<string, int> shoppingList = new ConcurrentDictionary<string, int>();
static async Task AddItemAsync(string item)
{
// 尝试添加或更新数量,线程安全
shoppingList.AddOrUpdate(item, 1, (key, oldValue) => oldValue + 1);
await Task.Yield(); // 模拟一点点耗时,让并发效果更明显
}
static async Task Main()
{
var tasks = new Task[10];
for (int i = 0; i < 10; i++)
{
tasks[i] = AddItemAsync("苹果");
}
await Task.WhenAll(tasks);
foreach (var item in shoppingList)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
}
}
注释说明:这段代码展示了如何使用ConcurrentDictionary
来安全地在多线程环境下添加购物清单项。即使多个线程同时尝试添加“苹果”,AddOrUpdate
方法也会确保不会有重复计数的问题。
总结:
-
多线程入门:线程是程序执行任务的基本单位,多线程允许程序同时执行多个任务,如同厨房里多位厨师同时准备不同菜肴,显著提升工作效率。通过创建和管理线程,你能使程序运行更加流畅,响应更快。
-
异步编程与Task:
async
和await
关键字是C#中异步编程的核心,它们使程序能在等待耗时操作(如网络请求、磁盘I/O)时释放当前线程去做其他工作,如同等待外卖时可以继续做家务,不白白浪费时间,从而优化程序的整体性能。 -
并发集合与线程安全:在多线程环境中,直接访问共享数据可能导致数据不一致性问题。
ConcurrentDictionary
等并发集合为此而生,它们内置同步机制,确保了多线程访问时的数据安全,有效避免了竞态条件,让数据操作既高效又可靠。
这些知识点相互支撑,构成了处理并发问题、提升程序效率与稳定性的坚实基础。掌握它们,你就能在编写高质量、高性能应用程序的道路上迈出重要一步。