现代应用程序通常需要执行复杂的计算或处理 I/O 操作,这些操作可能会导致主线程阻塞,从而降低用户体验。C# 提供了多线程与异步编程的多种工具,让我们能够高效地并发处理任务。本文将介绍 C# 中的多线程与异步编程,包括 Thread
类、任务并行库、async
和 await
异步编程,以及并行循环和 PLINQ。
1. 线程基础(Thread 类)
在 C# 中,Thread
类用于创建和管理独立的执行路径。每个线程都在单独的 CPU 核心上运行,可以并发处理多个任务。以下是 Thread
类的基本用法:
using System;
using System.Threading;public class Program
{public static void PrintNumbers(){for (int i = 1; i <= 5; i++){Console.WriteLine(i);Thread.Sleep(500); // 模拟工作负载}}public static void Main(){Thread thread = new Thread(PrintNumbers);thread.Start(); // 启动新线程for (int i = 10; i <= 15; i++){Console.WriteLine(i);Thread.Sleep(500);}}
}
在此示例中,主线程和新线程 thread
会并发执行,分别输出 1 到 5 和 10 到 15。
- 优点:
Thread
类提供了对底层线程的直接控制。 - 缺点:创建和管理大量线程的开销较大,并且不便于资源管理。
2. 任务并行库(Task Parallel Library)
任务并行库 (Task Parallel Library, TPL) 简化了多线程编程,提供了 Task
类来抽象和管理并发任务。Task
更轻量级,且由运行时负责资源调度。Task.Run
可用于并行执行任务。
using System;
using System.Threading.Tasks;public class Program
{public static void Main(){Task task = Task.Run(() =>{for (int i = 1; i <= 5; i++){Console.WriteLine($"Task: {i}");Task.Delay(500).Wait(); // 模拟工作负载}});task.Wait(); // 等待任务完成Console.WriteLine("Task completed.");}
}
使用 TPL 的好处是,Task
可以简化线程管理,减少代码的复杂性。Task.Wait()
用于等待任务完成,而 Task.WhenAll
和 Task.WhenAny
可以实现多个任务的同步或竞赛。
3. async 与 await 异步编程
C# 提供的 async
和 await
关键字可以帮助我们编写简洁且高效的异步代码。在异步方法中使用 await
可以让方法在等待异步任务完成时不阻塞主线程。
using System;
using System.Threading.Tasks;public class Program
{public static async Task PerformTaskAsync(){Console.WriteLine("Starting task...");await Task.Delay(2000); // 异步等待Console.WriteLine("Task completed.");}public static async Task Main(){await PerformTaskAsync();Console.WriteLine("Program completed.");}
}
在这个示例中,PerformTaskAsync
是一个异步方法,使用 await Task.Delay(2000)
模拟异步任务执行。在等待时,主线程并不会被阻塞,可以处理其他任务。
- 优点:
async
和await
简化了异步代码编写,避免了回调地狱问题。 - 应用场景:适合需要等待 I/O 操作、网络请求等长时间任务的场景。
4. 并行循环与 PLINQ
并行循环 和 PLINQ(Parallel LINQ) 是 C# 中并行处理数据集合的两种方式,它们在多核系统上能够显著提高处理速度。
并行循环
Parallel.For
和 Parallel.ForEach
可以并行地处理集合中的元素,适合用于处理计算密集型任务。
using System;
using System.Threading.Tasks;public class Program
{public static void Main(){Parallel.For(0, 5, i =>{Console.WriteLine($"Parallel loop: {i}");Task.Delay(500).Wait(); // 模拟工作负载});Console.WriteLine("Parallel loop completed.");}
}
在此示例中,Parallel.For
将 0 到 5 的迭代并行化执行。并行循环适用于处理大量数据的计算密集型任务。
PLINQ
PLINQ(Parallel LINQ)是 LINQ 的并行版本,它允许我们使用 LINQ 查询语法来处理集合,同时利用多核处理器并行执行查询。使用 .AsParallel()
即可将普通 LINQ 查询转为并行处理。
using System;
using System.Linq;public class Program
{public static void Main(){int[] numbers = Enumerable.Range(1, 10).ToArray();var squaredNumbers = numbers.AsParallel().Select(n => n * n).ToArray();foreach (var num in squaredNumbers){Console.WriteLine(num);}}
}
在此示例中,AsParallel()
将查询转换为并行操作,Select
中的运算会在多个线程上同时执行。这使得 PLINQ 特别适合处理大数据集的批量计算。
结论
C# 提供了多种方式来处理并发任务和异步操作,包括 Thread
、任务并行库 (TPL)、async
和 await
异步编程、并行循环和 PLINQ。
Thread
类 提供了底层线程控制。- 任务并行库 (TPL) 简化了并发任务管理。
async
和await
提供了简洁的异步编程支持,避免阻塞主线程。- 并行循环 和 PLINQ 适合处理计算密集型的集合数据。
通过掌握这些工具和技术,你可以编写高效、可扩展的多线程和异步 C# 程序,为用户提供更流畅的体验。
这篇博客介绍了 C# 中的多线程与异步编程基础。如果你有进一步的问题或需要更深入的示例,欢迎留言或联系我!