C# 中的并发与多线程:完整指南
现代应用程序需要高性能和快速响应。C# 中的并发(concurrency)和多线程(multithreading)是关键工具,能够同时执行多个任务、高效利用多核处理器并改善用户体验。本文将讲解从经典线程到现代 async/await 和 Parallel LINQ 的核心概念。
多线程基础:Thread 类和线程池
C# 中的多线程始于 System.Threading.Thread 类。每个线程代表进程内独立的执行路径。然而手动创建线程是一项昂贵的操作。为了优化,使用线程池(ThreadPool)来管理线程的复用。
手动创建线程示例:
using System;using System.Threading;
class Program{ static void Main() { Thread thread = new Thread(DoWork); thread.Start(); Console.WriteLine("主线程正在运行..."); thread.Join(); // 等待完成 }
static void DoWork() { Console.WriteLine("线程正在执行工作。"); }}更简单的用法推荐使用 ThreadPool:
ThreadPool.QueueUserWorkItem(state => { Console.WriteLine("线程池中的任务。");});重要提示: Thread 类提供低级 API 且不支持返回值。对于现代应用程序,请使用 Task。
Task 和 TPL(任务并行库)
TPL 库(System.Threading.Tasks)提供了高级抽象——Task。Task 表示可以返回值的异步操作。这是 C# 中现代并发的基础。
无返回值的 Task 示例:
using System;using System.Threading.Tasks;
class Program{ static async Task Main() { Task task = Task.Run(() => DoWork()); await task; Console.WriteLine("完成。"); }
static void DoWork() { Console.WriteLine("在 Task 中工作。"); }}带返回值的 Task:
Task<int> task = Task.Run(() => { int result = 0; for (int i = 0; i < 1000000; i++) result += i; return result;});int sum = await task;Console.WriteLine($"总和: {sum}");TPL 还包含 Parallel.For 和 Parallel.ForEach 用于并行处理集合:
Parallel.For(0, 10, i => { Console.WriteLine($"迭代 {i} 在线程 {Thread.CurrentThread.ManagedThreadId} 上");});Async/await:异步编程
async 和 await 关键字简化了异步代码的编写,使其看起来像同步代码。它们不会创建新线程,而是高效地切换执行上下文,释放线程用于其他任务。
异步方法示例:
using System;using System.Net.Http;using System.Threading.Tasks;
class Program{ static async Task Main() { string data = await FetchDataAsync("https://example.com"); Console.WriteLine(data); }
static async Task<string> FetchDataAsync(string url) { using HttpClient client = new HttpClient(); string result = await client.GetStringAsync(url); return result; }}使用规则:
- 带有
async的方法必须返回Task、Task<T>或void(仅用于事件处理程序)。