C#并行编程详解:Tasks.Parallel类核心方法与实战应用

蓝鲸
蓝鲸
发布时间:2026-10-15| 4人浏览过
原创

在多核时代,充分利用CPU资源是提升程序性能的关键。C#通过Task Parallel Library (TPL)提供了强大的并行处理能力。本文将重点解析System.Threading.Tasks.Parallel类,演示如何利用Parallel.Invoke并行调用不同方法,使用Parallel.For和Parallel.ForEach加速集合遍历,并通过线程局部变量解决并发累加问题,同时介绍循环中断与异常处理的正确姿势。

并行基础与TPL简介

.NET 4.0引入的并行扩展主要依赖TPL(Task Parallel Library)。与传统多线程需手动创建和管理线程不同,TPL面向“任务”抽象,自动调度线程资源,极大简化了并行开发的复杂度。数据并行是TPL的核心场景之一,指对源集合或数组元素同时执行相同操作。TPL通过System.Threading.Tasks.Parallel类提供实现,开发者只需编写类似串行循环的逻辑,底层会自动进行数据分区与线程分配。

Parallel.Invoke:并行调用多个独立任务

当需要同时执行多个互不依赖的操作时,可使用Parallel.Invoke。该方法接受一组Action委托,它们将在可用线程上并发执行。由于共享线程池,多个任务可能复用相同的线程,并非严格的一对一映射。

static void Main(string[] args)
{
    var watch = Stopwatch.StartNew();
    // 并行执行Run1和Run2,耗时约为两者中较长者而非总和
    Parallel.Invoke(Run1, Run2);
    watch.Stop();
    Console.WriteLine("并行开发总共耗时:{0} ms", watch.ElapsedMilliseconds);
}

static void Run1()
{
    Thread.Sleep(3000);
}

static void Run2()
{
    Thread.Sleep(5000);
}

为了验证线程复用情况,可观察以下示例:

ThreadLocal<string> threadName = new ThreadLocal<string>(() =>
{
    return "Thread" + Thread.CurrentThread.ManagedThreadId;
});

Action printThread = () =>
{
    bool isFirstTime = !threadName.IsValueCreated;
    Console.WriteLine($"{threadName.Value} {(isFirstTime ? "(首次)" : "(复用)")} ");
};

// 并行调用8次,通常不会看到8个不同的线程ID
Parallel.Invoke(printThread, printThread, printThread, printThread, printThread, printThread, printThread, printThread);
text-align:center">
p>

Parallel.For:优化For循环性能

对于固定迭代的循环结构,Parallel.For可将迭代任务分发到多个处理器核心并行执行。其返回值ParallelLoopResult包含IsCompleted属性,用于判断循环是否全部完成。

// 范围[0, 10)
ParallelLoopResult result = Parallel.For(0, 10, i =>
{
    Console.WriteLine($"迭代{i}, TaskID:{Task.CurrentId}, ThreadID:{Thread.CurrentThread.ManagedThreadId}");
    Thread.Sleep(10);
});
Console.WriteLine($"是否全部完成: {result.IsCompleted}");

在嵌套循环中,仅将最外层改为并行可获得显著提速。内部仍保持串行以保证单次迭代的原子性:

private void ParallelOptimization()
{
    // 外层并行分发大区间,内层串行处理子逻辑
    Parallel.For(0, 10000, i =>
    {
        for (int j = 0; j < 1000; j++)
        {
            for (int k = 0; k < 100; k++)
            {
                DoSomething();
            }
        }
    });
}

Parallel.ForEach:处理集合数据并行

针对IEnumerable集合,Parallel.ForEach更为适用。它能智能地对数据进行分区(Partitioning),每个分区内的计算串行执行,分区之间并行运算,有效减少线程切换开销。

var files = GetFiles();
Parallel.ForEach(files, file =>
{
    ProcessFile(file);
});

自定义分区策略同样支持,这在处理非标准集合时非常有用:

ConcurrentBag<int> results = new ConcurrentBag<int>();
// 手动指定数据范围区间 [0, 3000000)
Parallel.ForEach(Partitioner.Create(0, 3000000), range =>
{
    for (int m = range.Item1; m < range.Item2; m++)
    {
        results.Add(m * 2); // 示例计算
    }
});

线程局部变量与汇总策略

在并行累加等场景中,直接修改共享变量会导致竞态条件(Race Condition)。正确的做法是使用泛型版本的Parallel.For<TLocal>或Parallel.ForEach<TSource, TLocal>。

参数说明:

  • TLocal: 线程局部变量的类型。
  • localInit: 初始化局部变量,每个线程仅调用一次。
  • body: 循环体逻辑,返回更新后的局部变量值。
  • localFinally: 线程结束时的回调,用于将各线程结果安全地合并至全局变量(如使用Interlocked类)。

Parallel.For局部变量示例

从数值2开始累加:

int[] nums = Enumerable.Range(0, 10).ToArray();
long totalGlobal = 0;

Parallel.For<long>(0, nums.Length, 
    () => 2, // localInit: 初始值为2
    (j, loopState, subtotal) =>
    {
        subtotal += nums[j]; // 线程私有累加
        Console.WriteLine($"局部累加结果: {subtotal}");
        return subtotal;      // body返回新状态
    },
    (finalVal) =>
    {
        Interlocked.Add(ref totalGlobal, finalVal); // localFinally安全汇总
    });

Console.WriteLine($"最终总计: {totalGlobal}");

循环控制:Stop与Break

ParallelLoopState提供了两种终止循环的方式:

  • Stop(): 请求立即停止所有正在进行的迭代。已开始的迭代可能会继续运行直至完成当前单元,但不再接收新任务。
  • Break(): 声明“我已完成之前所有的迭代”。它会确保小于当前索引的所有迭代都能完整执行,之后停止更大数据的处理。这适用于需要保留前缀结果的场景。

并发取消与异常处理

可通过ParallelOptions.CancellationToken配合CancellationTokenSource来优雅地取消正在进行的并行任务。若任务因取消而退出,通常会抛出OperationCanceledException。

由于并行环境中任何线程都可能抛出异常,单个异常不足以反映全貌。推荐使用ConcurrentQueue<Exception>收集所有遇到的异常,循环结束后抛出一个包装所有异常的AggregateException,以便外部统一捕获和处理。

以上就是C#并行编程之Tasks.Parallel类的详细内容,更多关于C#并行优化与数据处理的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。