3

Lets say I have a List that has 10 Tasks that each call a rest API. I'd like to run the tasks in a method that returns an IAsyncEnumerable that yields as each call is returned. I don't know what order the calls will return in.

I've looked into IAsyncEnumerable and I'm not convinced it can do this. It seems to await each Task in turn and yield the result. I want to fire all 10 Tasks at once and yield in whatever order they come back in.

It's an interesting problem I think.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
FeeFiFoFum
  • 1,719
  • 1
  • 11
  • 18
  • 3
    You can use `Task.WhenAny` to wait for "any of the given tasks" to complete. I suspect that will help. – Jon Skeet Dec 07 '22 at 07:28
  • 1
    I think I've seen an example, where `Task.WhenAny` was called in a loop, removing the finished task from the list and looping until list is empty. – Fildor Dec 07 '22 at 07:47
  • 1
    Naive approach: https://dotnetfiddle.net/B8cJp4 – Fildor Dec 07 '22 at 09:03
  • There are at least two interesting semantic questions: How would you want cancellation to be handled? And how would you want exceptions to be handled? – Stephen Cleary Dec 09 '22 at 20:03

1 Answers1

1

I quickly fiddled a naive approach:

public static async IAsyncEnumerable<Task<T>> WhenEach<T>(IEnumerable<Task<T>> tasks)
{
    var taskList = new List<Task<T>>(tasks);
    while( taskList.Any() )
    {
        var task = await Task.WhenAny(taskList);
        taskList.Remove(task);
        yield return task;
    }
}

It may not be Production-Ready and have some quirks but as a platform to start from, it should be enough.

Fildor
  • 14,510
  • 4
  • 35
  • 67