C#中的Parallel.For

292 阅读2分钟

Parallel.For 是 .NET 提供的一种并行编程工具,用于在多核处理器上并行执行循环中的任务。它属于 System.Threading.Tasks 命名空间,是 Task Parallel Library (TPL) 的一部分。Parallel.For 可以显著提高循环的执行速度,特别是对于计算密集型任务。

什么是 Parallel.For

Parallel.For 方法用于并行执行一个指定次数的循环体。它的工作原理是将循环的迭代分配到多个线程上执行,从而充分利用多核处理器的性能。Parallel.For 提供了多种重载方法,支持不同的用法场景。

基本语法

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);
  • fromInclusive: 循环的起始索引(包含)。
  • toExclusive: 循环的结束索引(不包含)。
  • body: 要执行的循环体,该方法接受一个整数参数,表示当前的循环索引。

使用示例

示例1:简单并行循环

以下示例展示了如何使用 Parallel.For 并行执行一个简单的循环:

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        Parallel.For(0, 10, i =>
        {
            Console.WriteLine($"Iteration {i} executed on thread {Task.CurrentId}");
        });
    }
}

在这个示例中,Parallel.For 方法将 0 到 9 之间的迭代分配给多个线程并行执行,并打印每次迭代的索引和线程 ID。

示例2:并行计算

假设我们需要计算一个数组中每个元素的平方,可以使用 Parallel.For 来并行执行:

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        int[] numbers = new int[10];
        for (int i = 0; i < numbers.Length; i++)
        {
            numbers[i] = i;
        }

        Parallel.For(0, numbers.Length, i =>
        {
            numbers[i] = numbers[i] * numbers[i];
        });

        foreach (var number in numbers)
        {
            Console.WriteLine(number);
        }
    }
}

在这个示例中,Parallel.For 方法将数组的每个元素的平方计算分配给多个线程并行执行。

示例3:处理大型数据集

对于大型数据集,并行处理可以显著提高性能。以下示例展示了如何并行处理一个大型数组:

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        int[] data = new int[1000000];
        Parallel.For(0, data.Length, i =>
        {
            data[i] = i * 2;
        });

        Console.WriteLine("Data processing complete.");
    }
}

在这个示例中,Parallel.For 方法将处理 100万个元素的数组分配给多个线程并行执行。

示例4:使用局部变量

有时需要在每个线程中维护一个局部变量,可以使用 Parallel.For 的重载方法:

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        int[] data = new int[10];
        Parallel.For(0, data.Length, () => 0, (i, loopState, localSum) =>
        {
            localSum += i;
            data[i] = localSum;
            return localSum;
        }, localSum => Console.WriteLine($"Local sum: {localSum}"));
    }
}

在这个示例中,Parallel.For 方法使用了局部变量 localSum 来计算每个线程的局部和,并在循环结束后打印。

使用注意事项

1. 线程安全

在并行循环中,要特别注意线程安全问题。如果多个线程访问共享变量,可能会导致数据竞争和不一致的结果。可以使用锁或其他同步机制来确保线程安全。

object lockObj = new object();
Parallel.For(0, data.Length, i =>
{
    lock (lockObj)
    {
        // 线程安全操作
    }
});

2. 负载均衡

并行循环的性能取决于任务的负载均衡。如果某些任务执行时间明显长于其他任务,可能会导致性能下降。可以通过合理分配任务来优化性能。

3. 异常处理

Parallel.For 中的异常处理与普通循环不同。如果循环体中抛出异常,异常将被捕获并存储在 AggregateException 中:

try
{
    Parallel.For(0, 10, i =>
    {
        if (i == 5)
        {
            throw new InvalidOperationException("Test exception");
        }
    });
}
catch (AggregateException ex)
{
    foreach (var innerException in ex.InnerExceptions)
    {
        Console.WriteLine(innerException.Message);
    }
}

4. 性能测量

使用并行编程可以提高性能,但在某些情况下可能并不能显著改善,甚至可能变差。因此,在使用并行编程时,最好进行性能测量和对比,确保其确实提升了性能。

总结

Parallel.For 是 C# 中用于并行执行循环的一种强大工具。它可以显著提高计算密集型任务的性能,但需要注意线程安全、负载均衡和异常处理等问题。通过合理使用 Parallel.For,可以充分利用多核处理器的性能优势,编写高效的并行程序。

如果你有更多关于 Parallel.For 或其他并行编程的问题,请随时告诉我!