-1

Consider this piece of code:

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); });
        }
    }
}

I get the following output:

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

And a Polly.Timeout.TimeoutRejectedException is thrown at the very end. I can't really understand why it would take so long to execute? From the output it seems that the first 8 tasks execute in parallel, and then it gets really slow.

Without timeout policy or with optimistic timeout strategy it runs instantly. But in my case only pessimistic timeout policy can be used.

Using the latest Polly version, which is 6.0.1.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
picusiaubas
  • 115
  • 2
  • 9
  • what kind of issue are your trying to solve? why do you ever need this? – Zazaeil May 16 '18 at 12:46
  • Just the basic use case for timeout policy. I was trying to set a particular timeout on a database call and faced this problem. I posted a simplified example that illustrates the problem. – picusiaubas May 16 '18 at 12:51
  • 2
    Does setting `ThreadPool.SetMinThreads(50, 50);` at the start of `Main` make a difference? Why do you think that is? – mjwills May 16 '18 at 12:52
  • Is the call to the db (in your real-life case) synchronous and blocking the threads? (as Thread.Sleep does in the code in the question). In the case the db call is async, a simulation would want to use `Policy.TimeoutAsync` and `Task.Delay` (in place of `Thread.Sleep`) to simulate async calls to the db. (In the synchronous case, +1 to the other answers/comments around use and behaviour of the thread pool.) – mountain traveller May 16 '18 at 12:57
  • @mountaintraveller No, db call is synchronous. – picusiaubas May 16 '18 at 13:01
  • @mjwills That helped, thanks! – picusiaubas May 16 '18 at 13:54

1 Answers1

0

I think the way you add tasks to the list and then start them is not entirely correct.

Please see this answer (Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()) for clarification on the correct use of .Start().

So in your case all you really need to do is change the Add portion to this

for (var i = 0; i < 20; i++)
{
   tlist.Add(Task.Run(() => Test()));
}

This will solve your issue, and probably you will not need Polly. But you should be careful with the size of your task list. You will be utilizing the .net thread pool so you aren't taking the physical threads as it were but still the is a limit to how far you can push this.

EDIT:

You will also need to get rid of this part here

foreach (var task in tasks)
            task.Start();
Alex
  • 1,110
  • 8
  • 15