Home > Enterprise >  Run multiple tasks in parallel and cancel rest if any of them returns false .NET
Run multiple tasks in parallel and cancel rest if any of them returns false .NET

Time:06-02

Currently I have a code like this:

 bool task1Result = await RunTask1(data);
 if(!task1Result)
     return false;

 bool task2Result = await RunTask2(data);
 if(!task2Result)
     return false;

 bool task3Result = await RunTask3(data);
 if(!task3Result)
     return false;

 bool task4Result = await RunTask4(data);
 if(!task4Result)
     return false;

Added sample:

private async Task<bool> RunListOfTasks() {
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;

var tasks = new List<Task<bool>> { RunTask1(data, ct), RunTask2(data, ct), RunTask3(data, ct), RunTask4(data, ct) };
while (tasks.Any())
{
    var currentTask = await Task.WhenAny(tasks);
    if (!await currentTask)
    {
        ct.Cancel();
        return false;
    }
    tasks.Remove(currentTask);
}
return true;
}

Is it possible to run all of them in parallel and if one of them fails (like result is false), then stop processing the rest and return. Thanks

CodePudding user response:

The Task.WhenAny-in-a-loop is generally considered an antipattern, because of its O(n²) complexity. The preferred approach is to wrap your tasks in another set of tasks, that will include the functionality of canceling the CancellationTokenSource when the result is false. Then await the wrapper tasks instead of the initial tasks, and propagate their result.

An easy way to wrap the tasks is the Select LINQ operator:

private async Task<bool> RunListOfTasks()
{
    using CancellationTokenSource cts = new();

    List<Task<bool>> tasks = new()
    {
        RunTask1(data, cts.Token),
        RunTask2(data, cts.Token),
        RunTask3(data, cts.Token),
        RunTask4(data, cts.Token),
    };

    Task<bool>[] enhancedTasks = tasks.Select(async task =>
    {
        try
        {
            bool result = await task.ConfigureAwait(false);
            if (!result) cts.Cancel();
            return result;
        }
        catch (OperationCanceledException) when (cts.IsCancellationRequested)
        {
            return false;
        }
    }).ToArray();

    bool[] results = await Task.WhenAll(enhancedTasks).ConfigureAwait(false);
    return results.All(x => x);
}
  • Related