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