并行编程是现代软件开发中不可或缺的一部分,特别是在处理大量数据或进行计算密集型任务时。随着多核处理器的普及,C# 语言通过 .NET Framework 提供了强大的并行编程支持。本文将深入探讨 C# 中的并行编程,解释其概念、特点,并通过示例演示其用法。
System.Threading.Tasks.Parallel
是 .NET Framework 中的一个类,它提供了一组静态方法,用于并行执行循环(Parallel.For
和 Parallel.ForEach
)和代码块(Parallel.Invoke
)。这些方法可以自动分配任务到多个线程,利用多核处理器的能力,从而提高应用程序的性能。
C#static void Main(string[] args)
{
Parallel.For(0, 10, i =>
{
Console.WriteLine($"处理迭代 {i} 开始。");
// 模拟工作负载
System.Threading.Thread.Sleep(1000);
Console.WriteLine($"处理迭代 {i} 结束。");
});
}
C#static void Main(string[] args)
{
var items = new List<string> { "苹果", "香蕉", "橙子", "梨" };
Parallel.ForEach(items, item =>
{
Console.WriteLine($"正在处理 {item}。");
// 模拟工作负载
System.Threading.Thread.Sleep(1000);
});
}
C#static void Main()
{
Parallel.Invoke(
() => DoWork("任务1"),
() => DoWork("任务2"),
() => DoWork("任务3")
);
}
static void DoWork(string taskName)
{
Console.WriteLine($"{taskName} 开始。");
// 模拟工作负载
System.Threading.Thread.Sleep(1000);
Console.WriteLine($"{taskName} 结束。");
}
在这些示例中,Parallel.For
和 Parallel.ForEach
用于并行处理循环迭代,而 Parallel.Invoke
用于并行执行不同的方法调用。这些方法都是在后台自动管理线程和任务,使得开发者能够专注于业务逻辑的实现,而无需担心并行编程的复杂性。
并行编程在处理大量数据或需要大量计算的应用程序中尤其有用,可以显著提高性能和响应速度。然而,开发者在使用时也需要注意线程安全问题,确保共享资源的访问不会导致竞争条件或其他并发问题。
C#static void Main()
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
try
{
cancellationTokenSource.CancelAfter(3000);
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.CancellationToken = token;
// 假设我们有一个需要并行处理的数据集合
int[] data = Enumerable.Range(0, 100).ToArray();
Parallel.ForEach(data, parallelOptions, (item, state) =>
{
// 检查是否有取消请求
if (token.IsCancellationRequested)
{
// 抛出 OperationCanceledException 来响应取消请求
// 这将导致 Parallel.ForEach 退出
token.ThrowIfCancellationRequested();
}
// 模拟一些工作
Console.WriteLine($"Processing item {item}");
Thread.Sleep(1000); // 假装我们在这里做了一些工作
});
}
catch (OperationCanceledException ex)
{
Console.WriteLine("Operation was canceled!");
}
Console.ReadKey();
}
Parallel
类的原理基于 .NET Framework 中的任务并行库 (Task Parallel Library, TPL)。TPL 是一种高层次的抽象,用于并行执行代码。它允许开发人员利用多核处理器的能力,通过并行执行来提高应用程序的性能。以下是 Parallel
类原理的几个关键点:
TPL 使用一个任务调度器来管理任务的执行。默认情况下,它使用线程池 (ThreadPool) 来执行任务,但开发者可以自定义调度器以满足特定需求。任务调度器负责决定何时以及在哪个线程上执行任务。
.NET 的线程池实现了一种称为“工作窃取”的算法,其中空闲的线程可以从忙碌的线程“窃取”任务来执行。这有助于动态平衡负载,提高处理器核心的利用率。
Parallel.For
和 Parallel.ForEach
循环会将迭代分成多个区块,这些区块可以独立地在不同的线程上并行执行。TPL 动态决定这些区块的大小,以最小化线程之间的同步开销并优化性能。
TPL 会根据当前系统的资源状况(如 CPU 核心数量)来决定并行度,即同时执行的任务数量。它会尝试最大化 CPU 利用率,同时避免过多的线程创建导致的上下文切换开销。
当并行代码块中的多个任务抛出异常时,TPL 会将这些异常聚合到一个 AggregateException
实例中。这使得异常处理变得更加简单,因为开发者只需要处理一个异常实例,即可访问所有抛出的异常。
TPL 与 .NET 的取消框架集成,允许开发者使用 CancellationToken
来取消正在执行的并行操作。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!