You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中Polly悲观超时策略多线程执行变慢问题咨询

问题分析:Polly悲观超时导致任务执行骤降并抛出超时异常

先看你的测试代码:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Polly;
using Polly.Timeout;

namespace Test
{
    public class Program
    {
        public static async Task Main()
        {
            var tasks = new List<Task>();
            for (var i = 0; i < 20; i++)
            {
                var task = new Task(Test);
                tasks.Add(task);
            }
            foreach (var task in tasks) task.Start();
            await Task.WhenAll(tasks);
        }

        public static void Test()
        {
            Console.WriteLine($"Executing Test() at {DateTime.Now}");
            Policy.Timeout(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic)
                  .Execute(() => { Thread.Sleep(200); });
        }
    }
}

执行输出:

Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:21
Executing Test() at 2018-05-16 15:10:22
Executing Test() at 2018-05-16 15:10:23
Executing Test() at 2018-05-16 15:10:24
Executing Test() at 2018-05-16 15:10:24
Executing Test() at 2018-05-16 15:10:24
Executing Test() at 2018-05-16 15:10:25
Executing Test() at 2018-05-16 15:10:26
Executing Test() at 2018-05-16 15:10:26
Executing Test() at 2018-05-16 15:10:27
Executing Test() at 2018-05-16 15:10:27
Executing Test() at 2018-05-16 15:10:27
Executing Test() at 2018-05-16 15:10:28

最终抛出Polly.Timeout.TimeoutRejectedException,核心原因和你用的Polly 6.0.1版本的悲观超时实现,以及.NET线程池的默认配置直接相关:

核心问题:悲观超时的线程资源消耗

Polly 6.x版本的悲观超时策略(Pessimistic),是通过「额外线程监控超时」来实现的:它会把你的业务逻辑(也就是Thread.Sleep(200))放到一个单独的线程池线程执行,同时再启动另一个线程来监控超时时间——一旦到达超时阈值就终止执行业务的线程。

而.NET线程池默认的最小工作线程数是8,你一次性启动20个任务,每个任务要占用2个线程(一个执行业务,一个监控超时),8个初始线程瞬间就被占满了。

线程池在耗尽初始线程后,不会立刻批量创建新线程,而是有个「冷却机制」——默认每500ms才会新增一个线程。所以后续的任务只能排队等待线程分配,这就是你看到输出里时间间隔越来越大的原因。更糟的是,有些任务等待线程的时间就超过了你设置的2秒超时,直接触发了TimeoutRejectedException。

为什么乐观超时或无超时就正常?

  • 无超时策略:每个任务只占用1个线程池线程,你的业务逻辑仅休眠200ms,线程很快就能释放,线程池扩容压力极小,自然不会出现卡顿。
  • 乐观超时策略:它基于CancellationToken实现,不需要额外的监控线程——只是在业务逻辑中检查令牌是否超时,全程仅占用1个线程,不会浪费线程资源,因此不会出现线程池耗尽的问题。

针对你的场景的解决思路

如果业务必须使用悲观超时,在Polly 6.x版本中可以临时通过ThreadPool.SetMinThreads()调高线程池最小工作线程数来缓解,但这属于治标不治本的办法。更推荐的方案是升级Polly到7.x及以上版本——后续版本对悲观超时的实现做了优化,大幅减少了线程资源的消耗,从根源上解决这个问题。

内容的提问来源于stack exchange,提问作者picusiaubas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:06:39