What's the difference between returning void and returning a Task?
SLaks and Killercam's answers are good; I thought I'd just add a bit more context.
Your first question is essentially about what methods can be marked async
.
A method marked as
async
can returnvoid
,Task
orTask<T>
. What are the differences between them?
A Task<T>
returning async method can be awaited, and when the task completes it will proffer up a T.
A Task
returning async method can be awaited, and when the task completes, the continuation of the task is scheduled to run.
A void
returning async method cannot be awaited; it is a "fire and forget" method. It does work asynchronously, and you have no way of telling when it is done. This is more than a little bit weird; as SLaks says, normally you would only do that when making an asynchronous event handler. The event fires, the handler executes; no one is going to "await" the task returned by the event handler because event handlers do not return tasks, and even if they did, what code would use the Task for something? It's usually not user code that transfers control to the handler in the first place.
Your second question, in a comment, is essentially about what can be await
ed:
What kinds of methods can be
await
ed? Can a void-returning method beawait
ed?
No, a void-returning method cannot be awaited. The compiler translates await M()
into a call to M().GetAwaiter()
, where GetAwaiter
might be an instance method or an extension method. The value awaited has to be one for which you can get an awaiter; clearly a void-returning method does not produce a value from which you can get an awaiter.
Task
-returning methods can produce awaitable values. We anticipate that third parties will want to create their own implementations of Task
-like objects that can be awaited, and you will be able to await them. However, you will not be allowed to declare async
methods that return anything but void
, Task
or Task<T>
.
(UPDATE: My last sentence there may be falsified by a future version of C#; there is a proposal to allow return types other than task types for async methods.)
(UPDATE: The feature mentioned above made it in to C# 7.)
async/await - when to return a Task vs void?
Normally, you would want to return a
Task
. The main exception should be when you need to have avoid
return type (for events). If there's no reason to disallow having the callerawait
your task, why disallow it?async
methods that returnvoid
are special in another aspect: they represent top-level async operations, and have additional rules that come into play when your task returns an exception. The easiest way is to show the difference is with an example:
static async void f()
{
await h();
}
static async Task g()
{
await h();
}
static async Task h()
{
throw new NotImplementedException();
}
private void button1_Click(object sender, EventArgs e)
{
f();
}
private void button2_Click(object sender, EventArgs e)
{
g();
}
private void button3_Click(object sender, EventArgs e)
{
GC.Collect();
}
f
's exception is always "observed". An exception that leaves a top-level asynchronous method is simply treated like any other unhandled exception. g
's exception is never observed. When the garbage collector comes to clean up the task, it sees that the task resulted in an exception, and nobody handled the exception. When that happens, the TaskScheduler.UnobservedTaskException
handler runs. You should never let this happen. To use your example,
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
Yes, use async
and await
here, they make sure your method still works correctly if an exception is thrown.
For more information see: https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
When the method return void, is the same that a task?
If I am not wrong, Task.Run create a new thread where to execute the method.
Not exactly. Task.Run()
will run the code on a thread different from the UI thread (at least with the default TaskScheduler
). But it will not actually create a new thread in most cases, it will reuse an existing thread from the ThreadPool
.
Then why to use an async method, if with the Task, creating a new thread, I get what I want, not to block the main thread?
The point of async
, in the context of a UI application, is to be able to easily execute some code on the UI thread after and asynchronous operation completes.
So, if you made your method01Async
“awaitable”, that is, made it return a Task
:
private async Task method01Async()
{
await Task.Run(/* whatever */);
}
You could then await it from the btnAsync01_Click
method, if you made it `async:
private async void btnAsync01_Click(object sender, RoutedEventArgs e)
{
UpdateTxtLog("click button: " + System.DateTime.Now);
await method01Async();
UpdateTxtLog("after method01Async: " + System.DateTime.Now);
}
This way, the last line of the method will execute only after the Task
in method01Async
finishes executing. And it will execute on the UI thread.
In .Net 4.0, you could achieve similar effect using ContinueWith()
and Dispatcher.Invoke()
:
private void btnAsync01_Click(object sender, RoutedEventArgs e)
{
UpdateTxtLog("click button: " + System.DateTime.Now);
method01Async().ContinueWith(() =>
Dispatcher.Invoke(
new Action(() =>
UpdateTxtLog("after method01Async: " + System.DateTime.Now)));
}
I'm sure you'll agree this is much messier and less readable.
Also, if the async method access some shared variable, I must be careful with the concurrency, right?
Yes, you're right about that.
In fact, I use the same code without async and without await and the result is the same, the main program is not blocking and all works as I expect.
The result certainly is not what I thought your code is supposed to do. The last line of btnAsync01_Click
, will execute “after method01Async”, but it will not wait until the Task
started in that method finishes.
As a side note, there is no need to use async
in your method01Async
. Returning the Task
directly (or not, if you want to keep it void
-returning), will work the same:
private Task method01Async()
{
return Task.Run(/* whatever */);
}
Do I need to return anything from an async task?
As a rule, when a non-async method returns void
, its async counterpart should return Task
:
public static async Task PopulateMetrics()
According to Microsoft, you should use void
return from async methods only when you implement an event handler:
Void-returning async methods have a specific purpose: to make asynchronous event handlers possible. It is possible to have an event handler that returns some actual type, but that doesn't work well with the language; invoking an event handler that returns a type is very awkward, and the notion of an event handler actually returning something doesn't make much sense. Event handlers naturally return void, so async methods return void so that you can have an asynchronous event handler.
Is there a difference with Task.Run a void method and Task method returning null?
You should never return a null task; that should cause a runtime NullReferenceException
error.
You can use await
within an async void
method, but you cannot use await
to consume an async void
method (because you cannot await
void
).
I recommend that you review my async
intro blog post; it should help you get a better understanding of async
and await
.
am I disposing CancellationTokenSource correctly here?
Your start button needs to cancel/dispose the old cts
when it creates a new one.
Difference between Task and void methods (Non Async)
public Task DoWork() {}
can be awaited in an async call
public void DoWork() {}
don't
Correct way of returning a task in C#
If you're asking should I expose a property or method, then that entirely depends on what the Task
represents.
If the task is something done once per instance of the class, then having a Task
property is appropriate. Usually in this case, the property represents something about the instance, such as "my initialization is complete" or "I am done processing".
If the task is something that you need to do multiple times, then having a Task
-returning method is appropriate.
Task
-returning methods are vastly more common than Task
properties.
On a side note, avoid async void
and don't use Task.Run
unnecessarily.
Related Topics
No Console Output When Using Allocconsole and Target Architecture X86
String Concatenation VS String Builder. Performance
How to Return a File Using Web API
Linq Order by Null Column Where Order Is Ascending and Nulls Should Be Last
Should You Declare Methods Using Overloads or Optional Parameters in C# 4.0
ASP.NET MVC 4 Multiple Post via Different Forms
Why Isn't My Public Property Serialized by the Xmlserializer
Windows 7 and Vista Uac - Programmatically Requesting Elevation in C#
How to Save Image in Database Using C#
Uploading Objects to Google Cloud Storage Buckets in C#
How Abstraction and Encapsulation Differ
How to Pass Anonymous Types as Parameters
How to Get the Current User Directory
How to Return a Custom Http Status Code from a Wcf Rest Method