Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What should an async method do if a Task is conditionally executed?

Suppose I have a method that awaits a Task. This method also returns a Task. For example:

public async virtual Task Save(String path)
{
    if (NewWords.Any())
    {
        await FileManager.WriteDictionary(path, NewWords, true);
    }
    else await Task.Run(() => { });
}

Is the

else await Task.Run(() => { });

necessary here or am I free to leave it? Is there any difference if it is present/absent? Maybe there is some other approach to this I should take?

like image 681
Balázs Avatar asked Apr 08 '16 12:04

Balázs


People also ask

When an asynchronous method is executed?

When a asynchronous method is executed, the code runs but nothing happens other than a compiler warning.

What happens if we execute an asynchronous method but don't await it?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.

What happens in an async method?

An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.

Is an async method that returns task?

Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value. void , for an event handler.


2 Answers

It's worse than unnecessary, as you're spinning up a thread to do nothing and then waiting until after its finished doing nothing.

The simplest way to do nothing, is to do nothing. In an async method the method will still have returned a Task, but that Task will be completed already, so something awaiting it further up will get straight onto the next thing it needs to do:

public async virtual Task Save(String path)
{
    if (NewWords.Any())
    {
        await FileManager.WriteDictionary(path, NewWords, true);
    }
}

(Also, it would be more in line with convention if SaveAsync and WriteDictionaryAsync were the method names here). If not using async (and there's no need to here, but I understand it's an example) use Task.CompletedTask:

public virtual Task Save(String path)
{
    if (NewWords.Any())
    {
        return FileManager.WriteDictionary(path, NewWords, true);
    }
    return Task.CompletedTask;
}

If you are coding against an earlier framework than 4.6 and therefore don't have CompletedTask available, then Task.Delay(0) is useful as Delay special cases the value 0 to return a cached completed task (in fact, the same one that CompletedTask returns):

public virtual Task Save(String path)
{
    if (NewWords.Any())
    {
        return FileManager.WriteDictionary(path, NewWords, true);
    }
    return Task.Delay(0);
}

But the 4.6 way is clearer as to your intent, rather than depending on a quirk of implementation.

like image 135
Jon Hanna Avatar answered Nov 07 '22 02:11

Jon Hanna


It's not neccesary. The async is only needed if at least one await is used. Everything inside the method is executed synchronously except for the await part.

like image 27
AgentFire Avatar answered Nov 07 '22 01:11

AgentFire