具有悲观超时策略的 C# Polly 在多个线程上运行缓慢?

Posted

技术标签:

【中文标题】具有悲观超时策略的 C# Polly 在多个线程上运行缓慢?【英文标题】:C# Polly with pessimistic timeout strategy slow on multiple threads? 【发布时间】:2018-10-26 12:27:50 【问题描述】:

考虑这段代码:

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。 我真的不明白为什么要花这么长时间来执行?从输出看来,前 8 个任务并行执行,然后变得非常慢。 如果没有超时策略或乐观超时策略,它会立即运行。但就我而言,只能使用悲观超时策略。

使用最新的 Polly 版本,即 6.0.1。

【问题讨论】:

您要解决什么样的问题?你为什么需要这个? 只是超时策略的基本用例。我试图在数据库调用上设置特定的超时并遇到了这个问题。我发布了一个说明问题的简化示例。 Main 的开头设置ThreadPool.SetMinThreads(50, 50); 有什么不同吗?你认为这是为什么? 对数据库的调用(在您的实际情况中)是否同步并阻塞线程? (正如 Thread.Sleep 在问题代码中所做的那样)。在数据库调用是异步的情况下,模拟需要使用Policy.TimeoutAsyncTask.Delay(代替Thread.Sleep)来模拟对数据库的异步调用。 (在同步情况下,对线程池的使用和行为的其他答案/cmets +1。) @mountaintraveller 不,数据库调用是同步的。 【参考方案1】:

我认为您将任务添加到列表然后启动它们的方式并不完全正确。

请参阅此答案 (Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()) 以了解正确使用 .Start()。

因此,在您的情况下,您真正​​需要做的就是将 Add 部分更改为此

for (var i = 0; i < 20; i++)

   tlist.Add(Task.Run(() => Test()));

这将解决您的问题,并且您可能不需要 Polly。但是你应该小心你的任务列表的大小。您将使用 .net 线程池,因此您不会像以前那样使用物理线程,但这仍然是您可以推多远的限制。

编辑:

你还需要在这里去掉这部分

foreach (var task in tasks)
            task.Start();

【讨论】:

以上是关于具有悲观超时策略的 C# Polly 在多个线程上运行缓慢?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Polly 实现复杂策略(超时重试)

Polly

Polly断路器能否具有指数durationOfBreak?

Polly Timeout 乐观使用 HttpClientFactory。如何使用取消令牌?

弹性和瞬态故障处理库Polly

微服务之Polly熔断策略