1

I am abit confused when it comes to how a method should look like when dealing with async / task.

From my understanding, a method that just creates a new task doesnt need to be async since this would produce overhead as it wraps the hole thing in a new task.

So this:

async Task _doStuff()
{
    await Task.Run(()=> _stuff());
}

Is better this way:

Task _doStuff()
{
    return Task.Run(()=> _stuff());
}

However, it gets a bit more complicated, if there are some preconditionchecks Which way is better then?

async Task _doStuff()
{
    if(stuffWasDone)
        return;
    await Task.Run(()=> _stuff());
}

or

Task _doStuff()
{
    if(stuffWasDone)
        return Task.Run(()=> {}); // this could be a static-readonly in some helper like AsyncHelper.Empty(); as there is no FromResult for Task.

    return Task.Run(()=> _stuff());
}

1 Answer 1

4

You dont have to use Task.Run in order to generate a Task. A Task is a promise. If a Task doesn't need to execute, don't create one. Using Task.Run has the overhead of invoking an empty lambda on a threadpool thread, you don't need that. Simply returning should suffice.

You may also use Task.FromResult if no Task is actually needed:

Task DoStuffAsync()
{
    if(stuffWasDone)
    {
       return Task.FromResult(0);
    }

    return Task.Run(() => _stuff());
}

If you don't want to re-generate the Task over again, you can simply put it in a local variable:

private static Task _emptyTask = Task.FromResult(0);

As for your first example of await vs return await, you cannot say one is "better" then the other, as they serve different purposes. The former will asynchronously wait for the Task to complete before returning while the latter will return a hot task to the caller. This will matter in regards of exception handling. More so, if you're not going to be consuming the result of the task afterwards, using await will incur in a redundant generation of a state machine.

As another side note, wrapping synchronous methods in asynchronous wrappers is bad practice. Let the end user explicitly call Task.Run instead, don't fool them with async behavior.

Sign up to request clarification or add additional context in comments.

5 Comments

@CSharpie What do you by mean "simple return doesn't work"? Task.FromResult isn't a simple return statement.
@PatrickHofman You should never return null from a method returning Task. Instead, return a completed task, faulted task, cancelled task or just throw the exception. But remember no null.
@SriramSakthivel: Can you explain why?
@PatrickHofman Because a Task is a promise which acts as a contract with calling code. A Task returning null is unexpected behavior. Look throughout BCL async API's, you always get some form of a Task which describes the behavior of what occured inside the Task. null will surprise callers and will result in undefined behavior most of the time.
@PatrickHofman Because who cares about checking null for Task returned from a method? You can't await it(NRE will be thrown), or calling Wait will also result in NRE. NRE gives no information about what is null. Makes debugging worse.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.