c# ParallelOptions 的 MaxDegreeOfParallelism 和 CancellationToken

来源:这里教程网 时间:2026-02-21 17:38:45 作者:

MaxDegreeOfParallelism 设置为 -1 会发生什么

它不会“不限制并发数”,而是退回到默认行为:.NET 运行时根据逻辑处理器数量动态决定线程数,通常是

Environment.ProcessorCount
。设置
MaxDegreeOfParallelism = -1
等价于不设置该属性,不是“无上限”。真想压榨全部线程资源(比如 I/O 密集型场景),得明确设为一个足够大的正整数,但要注意这可能导致线程池饥饿。

CancellationToken 在 Parallel.ForEach 中如何真正生效

CancellationToken
不会自动中断正在执行的迭代项,只影响“是否启动新任务”。一旦某个
action
已开始运行,它必须自己检查
token.IsCancellationRequested
并主动退出。否则,即使调用
token.Cancel()
,循环仍会等所有已派发的任务完成才返回。

在循环体内部定期检查
token.ThrowIfCancellationRequested()
if (token.IsCancellationRequested) return;
避免在 long-running 同步操作(如
Thread.Sleep(5000)
)中忽略 token
若使用
async
操作,
Parallel.ForEach
本身不支持异步委托,需改用
Task.WhenAll
+
Partition
手动实现

ParallelOptions.MaxDegreeOfParallelism 和 CancellationToken 能一起用吗

能,而且推荐一起用——尤其在可控资源消耗 + 可中断的批处理场景中。但要注意两者作用域不同:

MaxDegreeOfParallelism
控制并行“宽度”,
CancellationToken
控制整体“生命周期”。它们互不干扰,但共同影响最终行为:

设置
MaxDegreeOfParallelism = 4
后,最多同时跑 4 个迭代;此时调用
token.Cancel()
,已运行的 4 个可能继续,但第 5 个起不再调度
若某次迭代中抛出未捕获异常,
Parallel.ForEach
默认立即停止调度新任务,并等待正在运行的完成(类似隐式 cancellation),但不会触发
CancellationToken
的回调
不要依赖
CancellationToken
来“限流”,它不控制并发度;也不要靠
MaxDegreeOfParallelism
实现取消逻辑
var options = new ParallelOptions
{
    MaxDegreeOfParallelism = 3,
    CancellationToken = cts.Token
};
try
{
    Parallel.ForEach(items, options, item =>
    {
        // 必须手动检查
        cts.Token.ThrowIfCancellationRequested();
        // 模拟工作
        Thread.Sleep(100);
        // 若此处耗时且不可中断,Cancel() 就形同虚设
    });
}
catch (OperationCanceledException)
{
    // 只有在 ThrowIfCancellationRequested 触发时才会进这里
    Console.WriteLine("被取消了");
}
并发控制和取消信号是两个正交维度,混用时最容易漏掉的是“任务体内没查 token”——看起来设置了
CancellationToken
,实际根本没响应。

相关推荐