Home > database >  Skipping async/await?
Skipping async/await?

Time:06-14

I'm trying to understand if there's an optimisation in skipping async/await in certain situations or whether this could lead to a pitfall. Code below is made up example but it'll help to simplify for my question and understanding.

Say I have the following code:

public async Task<string> CreateRandomString()
{
    var myTitleTask = GetTitle();

    var randomString = CreateRandomString();

    var myTitle = await myTitleTask;
    
    return myTitle   randomString;
}

private async Task<string> GetTitle()
{
    return await GetTitleFromWebServiceAsync();
}

It's possible to remove the async/await from the GetTitle() method like this:

public async Task<string> CreateRandomString()
{
    var myTitleTask = GetTitle();

    var randomString = CreateRandomString();

    var myTitle = await myTitleTask;
    
    return myTitle   randomString;
}

private Task<string> GetTitle()
{
    return GetTitleFromWebServiceAsync();
}

Does this optimise anything because we are delaying as long as possible to await the Task from GetTitle() and thus doing other work until we await or does this cause any problems?

In the second example I thought this was more optimise and better approach but just want to make sure I'm not falling into any pitfall. Thoughts or comments on this please?

CodePudding user response:

Does this optimise anything because we are delaying as long as possible to await the Task from GetTitle() and thus doing other work until we await or does this cause any problems?

Well, I'm not going to go into benchmarks but this is what I sometimes do. If I need to "scan" a folder for images or some files. I start tasks in a foreach loop of directories and enumerate through them to get the relevant files, exiting the loop and await them all i.e. look through each folder in parallel. Instead of Task t = Task.Run(() => foo()); we can always do as you suggested, simply return the task instead of awaiting it and then in the end await myTask or await myTasks

There are also other uses like in a microservices architecture, you might want to "fire and forget" about an order created, such that email service, notification service, etc... handle all that and you return success to the user. Pretty much just like you place an order on Amazon and you only get a thank you for placing the order. For a sequential function like yours, I don't see a benefit of awaiting it on the 3rd line or the 5th line. It really depends on the code.

CodePudding user response:

It's possible to remove the async/await from the GetTitle() method like this:

Yes, and it is perfectly safe to do so.

Does this optimise anything because we are delaying as long as possible to await the Task from GetTitle() and thus doing other work until we await or does this cause any problems?

They are directly equivalent, skipping a async/await should be slightly more efficient, but I would expect the difference to be minimal. I would recommend doing some benchmarking if you are interested in actual numbers.

CodePudding user response:

Yes, when you find yourself only using await in the return statement, removing the async keyword from the method signature optimizes performance and bundle size. The C# compiler turns each method marked with async to a separate class that inherits IAsyncStateMachine! It basically divides the async method into several synchronous portions(2 awaits = 3 portions) and executes each portion depending on the class state. Thus, having modified the method to a class, an overhead of 100 bytes is added to your final bundle size(usually a very minor problem nowadays). And there is also the performance overhead of the runtime having to switch threads when the await keyword is present. So returning the task without awaiting it when possible will result in less context-switching, which is quite expensive.

  • Related