Async Await Return Task

async await return Task

async methods are different than normal methods. Whatever you return from async methods are wrapped in a Task.

If you return no value(void) it will be wrapped in Task, If you return int it will be wrapped in Task<int> and so on.

If your async method needs to return int you'd mark the return type of the method as Task<int> and you'll return plain int not the Task<int>. Compiler will convert the int to Task<int> for you.

private async Task<int> MethodName()
{
await SomethingAsync();
return 42;//Note we return int not Task<int> and that compiles
}

Sameway, When you return Task<object> your method's return type should be Task<Task<object>>

public async Task<Task<object>> MethodName()
{
return Task.FromResult<object>(null);//This will compile
}

Since your method is returning Task, it shouldn't return any value. Otherwise it won't compile.

public async Task MethodName()
{
return;//This should work but return is redundant and also method is useless.
}

Keep in mind that async method without an await statement is not async.

async Task then await Task vs Task then return task

It is almost the same (in terms of threads etc.). But for the second one (using await) a lot more overhead will be created by the compiler.

Methods declared as async and using await are converted into a state machine by the compiler. So when you hit the await, the control flow is returned to the calling method and execution of your async method is resumed after the await when the awaited Task has finished.

As there is no more code after your await, there is no need to use await anyway. Simply return the Task is enough.

Should I use async if I'm returning a Task and not awaiting anything

No, you should not just add async to method without await - there is even compiler warning for it.

You also should not needlessly add await inside such method as it will make compiler to generate significantly more complicated code for the method with some related performance implications.

There is no observable difference between two patterns from timing point of view - task will still run asynchronously and you still be able to await immediately or at later point in caller.

There is one difference I can think of - if you return task directly caller may use ConfigureAwait(false) and it will finish on other thread. When you await that task inside you method that method controls where code after await is executed.

Note that cost of method with single await at the end is not significantly worse than one without - so if you prefer for coding style consistent usage of async on all asynchronous methods it is likely fine except rare time critical pieces.

How to return a result from an async task?

Your method should return Task<string> , not Task:

public async Task<string> UploadInvoice(string assessment, string fileName)
{
//Do stuff
return string;
}

Which is the proper way for async method returns task?

I think you may not fully understand why anyone would want to use async. Async .Net allows the freeing up of threads that would normally be waiting on some external action to take place (network call or hard disk call). Normally windows uses I/O Completion Ports for these calls and has recently added async/await keywords to allow .Net access to native asynchronous calls. That being said there is a little overhead when using async as the runtime has to create a state-machine to keep track of a threads current state before assigning the await'd thread a new task.

Thus any async tasks that aren't using a I/O Completion Port are most likely doing more harm than good.

//async methods where I'm confused with
public Task<string> GetStringAsync(int i)
{
return Task.FromResult<string>(GetString(i));
}

Well let me correctly code this into an async method:

//async methods where I'm confused with
public async Task<string> GetStringAsync(int i)
{
return await Task.FromResult<string>(GetString(i));
}

Still bad, because there is no reason to use async; unless I'm mistaken about how Task.FromResult() works, this has additional overhead for no benefit.

I'm just going to rewrite them all as async and then give my understanding of what affect they have.

public async Task<string> GetStringAsync(int i)
{
Task<string> task = new Task<string>(() => GetString(i));
await task.Start();
return task;
}

It's extremely rare that you should be creating and starting your own tasks, it's not a good idea.

public Task<string> GetStringAsync(int i)
{
var tcs = new TaskCompletionSource<string>();
tcs.SetResult(GetString(i));
return tcs.Task;
}

The TaskCompletionSource was primarily designed to wrap current asynchronous into the async/await pattern. Since this isn't wrapping any type of asynchronous action there is no performance benefit.

public string GetString(int i)
{
return "Testing number " + i.ToString();
}

This is your best bet. Don't use async/await unless you actually need to.

Stephen Cleary has a great set of Posts that talk about Tasks and Async, I highly recommend you read through it before diving into Async in .Net.

Why returning Task.CompletedTask failed to compile in an async method?

Your method could functionally be condensed down to this.

public static Task F() 
{
return Task.Delay(1000);
}

Returning an Task.CompletedTask instance is only useful if these apply:

  • you do not want to use async/await
  • your method returns a Task (effectively void if you were to make it not asynchronous)
  • your code has logic where a task might not be returned

Example:

public static Task F() 
{
if (someConditionToShortCircutTheMethod)
return Task.CompletedTask;

// rest of logic
return Task.Delay(1000);
}

As soon as you make your method async then the fact that a Task is actually being returned is abstracted. This can make the code easier to work with especially if there are multiple points where the code waits for I/O operations to complete.

public static async Task F() 
{
if (someConditionToShortCircutTheMethod)
return;

// rest of logic
await Task.Delay(1000);
await Task.Delay(1000);
// no return necessary, async Task has a similar flow as return type void
}

I also recommend reviewing these previous questions:

  • How and when to use ‘async’ and ‘await’
  • Understanding async / await in C#

return Task.Run in an async method

Simple; either don't make it async:

private static Task<int> TaskOfTResult_MethodAsync()
{
return Task.Run(() => ComplexCalculation());
}

or await the result:

private static async Task<int> TaskOfTResult_MethodAsync()
{
return await Task.Run(() => ComplexCalculation());
}

(adding the await here is more expensive in terms of the generated machinery, but has more obvious/reliable exception handling, etc)

Note: you could also probably use Task.Yield:

private static async Task<int> TaskOfTResult_MethodAsync()
{
await Task.Yield();
return ComplexCalculation();
}

(note that what this does depends a lot on the sync-context, if one)

await Task.CompletedTask vs return

Let's look the question from the consumer-side.

If you define an interface, which imposes an operation that returns a Task then you don't say anything about how it will be calculated / executed (so, there is no async access modifier in the method signature). It is an implementation detail.

Interface

public interface ITest
{
Task Test();
Task<bool> IsTest();
}

So, it is up to you how you implement the interface.

You can do it in a synchronous way, when there won't be any AsyncStateMachine generated because of the absence of the async keyword.

Implementation #1

public class TestImpl : ITest
{
public Task Test()
{
return Task.CompletedTask;
}

public Task<bool> IsTest()
{
return Task.FromResult(true);
}
}

Or you can try to implement it in an asynchronous way but without await operators. Here you will receive CS1998 warnings.

Implementation #2

public class TestImpl : ITest
{
public async Task Test()
{
return;
}

public async Task<bool> IsTest()
{
return true;
}
}

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

In other words this implementation does not define a state machine. An async method is divided into different states based on the await keywords:

  • before_the_await_1,
  • after_the_await_1_but_before_the_await_2
  • after_the_await_2_but_before_the_await_3
  • ...

If you haven't got any await then you would have a single state, which would run in sync (there is no need to preserve state, execute async operation and then call MoveNext()).


Or you can try to implement it in an asynchronous way with await operators.

Implementation #3

public class TestImpl : ITest
{
public async Task Test()
{
await Task.CompletedTask;
}

public async Task<bool> IsTest()
{
return await Task.FromResult(true);
}
}

In this case there will be an async state machine but it won't be allocated on the heap. By default it is a struct and if it finishes in sync then we don't need to allocate them on the heap to extend its life out of the scope of the method.

For further information please read these articles:

  • Async/await in .NET Core 3.x
  • Async ValueTask Pooling in .NET 5
  • Dissecting the async methods in C#


Related Topics



Leave a reply



Submit