Search code examples
c#performanceasync-awaitconcurrency

How to parallel process multiple async task foreach loop


How can I simultaneously process multiple tasks in a forach each loop, the isconnected is set by the await item.GetIsConnected() call. At the moment the refresh is slow, so I would like for them to process simultaneously.

Before:

private async void Refresh()
{
    foreach (var item in Cars.ToList<Carnet>())
    {
        await item.GetIsConnected();
        if (item.IsConnected)
        {
            await item.GetCarDetailsAsync();
        }
    }
}

After:

private async void Refresh()
{
    List<Task> listOfTasks = new List<Task>();
    foreach (var item in Cars.ToList<Carnet>())
    {
        listOfTasks.Add(item.GetIsConnected());
        if (item.IsConnected)
        {
            await item.GetCarDetailsAsync();
        }
    }
    await Task.WhenAll(listOfTasks);
}

Solution

  • Since you are not awaiting the call to GetIsConnected() in your AFTER example, the loop will continue and the value may or may not be checked against what it would be once the call to GetIsConnected() is finished, what I think you'd want to do is add another method with a return type of Task and let the method call GetIsConnected() and await it inside the method then call GetCarDetailsAsync() if necessary:

    //changed to return type of Task, as async void should be avoided
    //unless this is an event handler method
    private async Task Refresh()
    //private async void Refresh() //change to this if event handler
    {
        List<Task> listOfTasks = new List<Task>();
        foreach (var item in Cars.ToList<Carnet>())
        {
            listOfTasks.Add(GetCarDetails(item));        
        }
        await Task.WhenAll(listOfTasks).ConfigureAwait(false);
    }
    
    //method to await the call to GetIsConnect() 
    //and then call GetCarDetailsAsync() if necessary
    private async Task GetCarDetails(Carnet c)
    {
        await c.GetIsConnected();
        if (c.IsConnected)
        {
            await c.GetCarDetailsAsync();
        }
    }