跳转到主内容
极星编程网:以代码为星,赴技术山海!

c# Parallel.Invoke 的用法 c#如何并行执行多个方法

Parallel.Invoke 是 .NET 中一次性并行执行多个无返回值、无依赖关系 Action 委托的方法,适用于日志写入、缓存刷新等彼此独立的任务;不适用于需返回值、顺序控制或并发限制的场景。 Parallel.Invoke 是什么,什么时候该用它
Parallel.Invoke
是 .NET 中用于**一次性并行执行多个无返回值、无依赖关系的 Action 委托**的便捷方法。它适合“几个独立任务,谁先做完谁先走”的场景,比如同时写日志、刷新缓存、发送通知——彼此不传参、不等结果、也不共享可变状态。 它不是万能替代
Task.Run
或
Parallel.ForEach
的方案。如果任务需要返回值、有执行顺序要求、或要控制并发数,
Parallel.Invoke
反而会掩盖问题。 基本用法和参数传递陷阱 直接传入多个
Action
即可,但要注意闭包捕获变量的问题:
int i = 0; Parallel.Invoke( () => Console.WriteLine($"Task A: {i}"), () => Console.WriteLine($"Task B: {i}"), () => { i = 42; Console.WriteLine("Task C done"); } );
上面代码中,A 和 B 极可能都输出
0
(取决于调度时机),但 C 修改了
i
,而 A/B 并不感知——这不是线程安全问题,而是典型的**变量捕获时机错误**。 正确做法是为每个委托提供独立副本: 用
let
式局部变量(C# 7+):
var localI = i; () => Console.WriteLine(localI);
避免在 lambda 外部修改被闭包捕获的变量 若需共享状态,改用
ConcurrentDictionary
、
Interlocked
等线程安全类型 异常处理:一个失败,全部中断
Parallel.Invoke
内部使用
AggregateException
包装所有子任务异常。只要任一委托抛出异常,其余正在运行的任务会被取消(尽力而为),且最终只抛出一个
AggregateException
。 C知道 CSDN推出的一款AI技术问答工具 下载 这意味着: 不能靠 try/catch 单个 lambda 来隔离错误 必须在外层 catch
AggregateException
,再遍历
.InnerExceptions
处理 若某个任务耗时很长且已出错,其他短任务也会被强行终止——这不是“超时控制”,而是“故障传播”
try { Parallel.Invoke( () => { throw new InvalidOperationException("First fail"); }, () => Thread.Sleep(2000) // 这个会被中断 ); } catch (AggregateException ae) { foreach (var ex in ae.InnerExceptions) { Console.WriteLine(ex.Message); } }
性能与替代方案对比
Parallel.Invoke
底层复用
ThreadPool
,启动开销小,但缺乏细粒度控制: 无法设置最大并行度(
MaxDegreeOfParallelism
),默认由调度器决定 不支持取消令牌(
CancellationToken
)直接传入——得手动在每个 Action 里检查 比手写
Task.Run
+
Task.WhenAll
更简洁,但后者能统一 await、支持返回值、天然集成取消逻辑 简单并行调用,
Parallel.Invoke
足够;一旦需求变复杂(比如要等全部完成再做下一步、要限制最多跑 3 个、要记录每个结果),就该切到
Task.WhenAll
或
ParallelOptions
配合
Parallel.ForEach
。 真正容易被忽略的是:它不保证执行顺序,也不保证 CPU 密集型任务一定更快——如果所有任务都在争抢同一块锁或磁盘 I/O,加并行反而更慢。

相关文章