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

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

标签: c#multithreadingperformancetimeoutpolly

解决方案


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

请参阅此答案(关于 Task.Start() 、 Task.Run() 和 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();

推荐阅读