-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Making "Process asynchronous tasks as they complete" easy by using IAsyncEnumerable #61959
Comments
Tagging subscribers to this area: @dotnet/area-system-threading-tasks Issue DetailsBackground and motivationCurrently, if we need to "Process asynchronous tasks as they complete" then we need to write lots of unnecessary codes and its not straight forward, something like below. // Using currently available APIs
List<Task<int>> downloadTasks = downloadTasksQuery.ToList();
while (downloadTasks.Any())
{
Task<int> finishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(finishedTask);
Process(await finishedTask);
} API Proposalnamespace System.Threading.Tasks
{
public class Task : IAsyncResult, IDisposable
{
public static IAsyncEnumerable<Task> WhenAnyAsEnumerable(params Task[] tasks); // Please change the name, this is not a good name for this method :)
public static IAsyncEnumerable<Task> WhenAnyAsEnumerable(IEnumerable<Task> tasks);
public static IAsyncEnumerable<Task<TResult>> WhenAnyAsEnumerable(params Task<TResult>[] tasks);
public static IAsyncEnumerable<Task<TResult>> WhenAnyAsEnumerable(IEnumerable<Task<TResult>> tasks);
}
} API Usage// Using new available APIs
await foreach (var finishedTask in Task.WhenAnyAsEnumerable(downloadTasksQuery))
{
Process(await finishedTask);
} Alternative DesignsNo response RisksNo response
|
This method already exists in |
@Vijay-Nirmal a name that might be more suitable for the |
You can achieve the same behavior with TaskCompletionPipe that has native support of |
Looks good as proposed namespace System.Threading.Tasks;
public class Task
{
public static IAsyncEnumerable<Task> WhenEach(params Task[] tasks);
public static IAsyncEnumerable<Task> WhenEach(params ReadOnlySpan<Task> tasks);
public static IAsyncEnumerable<Task> WhenEach(IEnumerable<Task> tasks);
public static IAsyncEnumerable<Task<TResult>> WhenEach(params Task<TResult>[] tasks);
public static IAsyncEnumerable<Task<TResult>> WhenEach(params ReadOnlySpan<Task<TResult>> tasks);
public static IAsyncEnumerable<Task<TResult>> WhenEach(IEnumerable<Task<TResult>> tasks);
} |
Nit: missing
|
I wonder what is the benefit here. Wouldn't IEnumerable be cheaper? At first look I thought this is going to return the value instead of the task because we're awaiting that one on MoveNextAsync. public static IAsyncEnumerable<TResult> WhenEach<TResult>(IEnumerable<Task<TResult>> tasks) |
You'd block synchronously in MoveNext waiting for the next task to complete.
It's returning the completed task, just like with WhenAny. That gives the consumer the ability to examine / use the completed Task however they like. |
If I'm not mistaken,
So what I'm saying is that IAsyncEnumerable<T> WhenEach(Task<T>[] tasks) {
foreach (Task<T> task in tasks.OrderByCompletion())
yield return await task;
}
} |
@alrz, how would you propose for I'm not understanding the aversion to using |
Note I'm talking about the the implementation in AsyncEx |
Which allocates a new TCS / Task for every input: |
EDITED on 1/23/2024 by @stephentoub:
Background and motivation
Currently, if we need to "Process asynchronous tasks as they complete" then we need to write lots of unnecessary codes and its not straight forward, something like below.
API Proposal
API Usage
Alternative Designs
No response
Risks
No response
Updates
(Others can edit this section and add more info)
WhenEach
name suggested by @theodorzoulias, [API Proposal]: Making "Process asynchronous tasks as they complete" easy by using IAsyncEnumerable #61959 (comment)The text was updated successfully, but these errors were encountered: