Skip to content

Instantly share code, notes, and snippets.

@guitarrapc
Created April 15, 2022 04:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guitarrapc/a38c02cdaee0273a3181410f3aef2bf8 to your computer and use it in GitHub Desktop.
Save guitarrapc/a38c02cdaee0273a3181410f3aef2bf8 to your computer and use it in GitHub Desktop.
public static class TaskExtentions
{
public static Task<TResult[]> WhenAllFailFast<TResult>(IEnumerable<Task<TResult>> tasks)
{
return WhenAllFailFast(tasks.ToArray());
}
public static Task<TResult[]> WhenAllFailFast<TResult>(params Task<TResult>[] tasks)
{
if (tasks is null) throw new ArgumentNullException(nameof(tasks));
if (tasks.Length == 0) return Task.FromResult(new TResult[0]);
var results = new TResult[tasks.Length];
var remaining = tasks.Length;
var tcs = new TaskCompletionSource<TResult[]>(
TaskCreationOptions.RunContinuationsAsynchronously);
for (int i = 0; i < tasks.Length; i++)
{
var task = tasks[i];
if (task == null) throw new ArgumentException(
$"The {nameof(tasks)} argument included a null value.", nameof(tasks));
HandleCompletion(task, i);
}
return tcs.Task;
async void HandleCompletion(Task<TResult> task, int index)
{
try
{
var result = await task.ConfigureAwait(false);
results[index] = result;
if (Interlocked.Decrement(ref remaining) == 0)
{
tcs.TrySetResult(results);
}
}
catch (OperationCanceledException)
{
tcs.TrySetCanceled();
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
}
public static Task WhenAllFailFast(IEnumerable<Task> tasks)
{
return WhenAllFailFast(tasks.ToArray());
}
public static Task WhenAllFailFast(params Task[] tasks)
{
if (tasks is null) throw new ArgumentNullException(nameof(tasks));
if (tasks.Length == 0) return Task.CompletedTask;
var remaining = tasks.Length;
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
for (int i = 0; i < tasks.Length; i++)
{
var task = tasks[i];
if (task == null) throw new ArgumentException(
$"The {nameof(tasks)} argument included a null value.", nameof(tasks));
HandleCompletion(task, i);
}
return tcs.Task;
async void HandleCompletion(Task task, int index)
{
try
{
await task.ConfigureAwait(false);
if (Interlocked.Decrement(ref remaining) == 0)
{
tcs.TrySetResult(true);
}
}
catch (OperationCanceledException)
{
tcs.TrySetCanceled();
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment