C# – When the method return void, is the same that a task

async-ctpasynchronousc

I am trying the async CTP, the versión 4.5 that allow use async methods without needing to write the Begin/End methods.

My first probe is to execute an async method that return void. I see a few examples and do the following:

private void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("click button: " + System.DateTime.Now);
    method01Async();
    UpdateTxtLog("after ethod01Async: " + System.DateTime.Now);
}

private async void method01Async()
{
    await TaskEx.Run(() =>
    {
        UpdateTxtLog("Enter method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("exit method01Async: " + System.DateTime.Now);
    });
}

In my WPF project I have a textBox where to see the results and a button that execute the async method.

In the async method, I use await, that is need because the method is async, and the TasEx.Run to create a new thread in which execute the code.

My doubt is in this point. In a few examples that I see of how to create an async method that returns void, use this way, the Task.Run or TaskEx.Run.

If I am not wrong, Task.Run create a new thread where to execute the method. 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?

Also, if the async method access some shared variable, I must be careful with the concurrency, right? So I don't know the advantage of using async methods, at least in this case.

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 method is this:

private void method01Async()
{
    TaskEx.Run(() =>
    {
        UpdateTxtLog("Enter method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("Exit method01Async: " + System.DateTime.Now);
    });
}

My question is, this is the correct way to use async when the method return void?

Best Answer

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 */);
}