0

The Task.WaitAny is not working as expected. I have a very simple application as below:

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        List<Task> _TaskList = new List<Task>();
        int iTaskIndex;

        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("--------------------------------");

            if (_TaskList.Count >= 3)
            {
                iTaskIndex = Task.WaitAny(_TaskList.ToArray(), stoppingToken);
                // Not working as expected,
                // expecting this will result index of task which has completed

                _logger.LogInformation("iTaskIndex - {0}", iTaskIndex);
                if (iTaskIndex >= 0)
                {
                    _TaskList.RemoveAt(iTaskIndex);
                }
            }

            _TaskList.Add(Task.Factory.StartNew(() => TimeConsumingTask()));

            await Task.Delay(1000, stoppingToken);
        }
    }

    private async void TimeConsumingTask()
    {
        _logger.LogInformation("TimeConsumingTask started {task} running at: {time}",
            Task.CurrentId, DateTimeOffset.Now);
        await Task.Delay(1000 * 60);
        _logger.LogInformation("TimeConsumingTask completed {task} running at: {time}",
            Task.CurrentId, DateTimeOffset.Now);
    }
}

At any given moment I should not have more than 3 tasks running simultaneously. I am deriving the index of completed task as:

iTaskIndex = Task.WaitAny(_TaskList.ToArray(), stoppingToken);

I am expecting that it will return index of completed task only. But I am getting index 0 everytime. The Task.WaitAny method describes:

Waits for any of the provided System.Threading.Tasks.Task objects to complete execution unless the wait is cancelled.

Am I missing something, or my understanding is not correct?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
SidD
  • 5,697
  • 4
  • 18
  • 30
  • 1
    The task at index 0 will be completing first every time. – Johnathan Barclay Sep 17 '21 at 15:34
  • 4
    You almost certainly shouldn't be using [`Task.Factory.StartNew` here](https://stackoverflow.com/questions/38423472/what-is-the-difference-between-task-run-and-task-factory-startnew) – Liam Sep 17 '21 at 15:36
  • 3
    `Task.WaitAny` is blocking. So rather than *3 tasks running simultaneously* you never have more than one task running ever. – Liam Sep 17 '21 at 15:37
  • Does this answer your question? [How to limit the Maximum number of parallel tasks in c#](https://stackoverflow.com/questions/36564596/how-to-limit-the-maximum-number-of-parallel-tasks-in-c-sharp) – Liam Sep 17 '21 at 15:38
  • 7
    1. Use `Task.Run` instead of `StartNew`. 2. Use `async Task` instead of `async void`. 3. Use `Task.WhenAny` instead of `Task.WaitAny`. 4. Profit! – Stephen Cleary Sep 17 '21 at 16:11
  • What are you *actually* trying to do? Whatever it is, there are easy ways to do it. Where do those "tasks" come from? Do you have an incoming list of jobs/messages that have to be processed? Several timer jobs, but you only want to execute up to 3 of them at a time? Something else? – Panagiotis Kanavos Sep 21 '21 at 09:55

0 Answers0