设置 MaxDegreeOfParallelism = -1 会退回到默认行为,即按逻辑处理器数(通常为 Environment.ProcessorCount)动态调度;CancellationToken 仅阻止新任务启动,已运行任务需手动检查 token 才能响应取消。

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,实际根本没响应。










