Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need help refactoring this basic async-await loop

Tags:

c#

async-await

So I have a business object that supports a "Save"-method which does some IO to some device. I then have a list of those objects which I want to save asynchronously in a batch. My code now looks like this:

    public async Task Save()
    {
        foreach (var element in Elements)
        {
            await element.Save();
        }
    }    

Now this results in n number of awaits, and I know that each await causes a bit of CPU overhead. I want to eliminate this and only have one single await. How do I refactor to achieve this?

like image 598
Nilzor Avatar asked Dec 13 '22 00:12

Nilzor


1 Answers

Well, you could call Save() on everything and then await all of them finishing using Task.WhenAll:

public async Task Save()
{
    await Task.WhenAll(Elements.Select(x => x.Save());
} 

or if you really don't do anything else, just:

public Task Save()
{
    return Task.WhenAll(Elements.Select(x => x.Save());
} 

EDIT: If you want to do them serially, use the code you've already got. It's worth noting that the way async/await has been designed, awaiting a call which actually completes synchronously (e.g. a cache hit, or in your case dirty checking) is really cheap. It doesn't need to do any task scheduling, create a continuation or anything like that. You say:

If I have a list of 10000 objects, and only 1 is dirty, I will end up with 9999 unnecessary async-awaits, which I suspect will be significant.

As ever, suspicions about performance bottlenecks are pretty much meaningless - what's important is evidence about performance bottlenecks. Have you tried the existing code and measured the cost? If not, I strongly suggest you do that before changing anything.

like image 161
Jon Skeet Avatar answered Dec 29 '22 15:12

Jon Skeet