When not to return Task in async methods?

Asked

Viewed 2,510 times

15

Normally, in some time-consuming tasks, I use asynchronous methods:

public async Task myLongRunningOperation(int i) { ... }

However, in what situations I don’t necessarily need to return a Task?

public async void myLongRunningOperation(int i) { ... }

What is the difference and impact on the declaration of the above two methods?

  • Related https://answall.com/q/148940/2541

  • Related link https://github.com/dotnet/roslyn/issues/13897

3 answers

16


Every method async should rather return a Task - whether or not to wait for its end.

A method async - beyond the obviousness of being an asynchronous method - it means that a new Thread to perform its action. And for you to have control of the life cycle of this task, your method returns a type Task so that you can know when this task is over, if you want to finish with its execution or even to know what it has returned.

The problem of creating a method async void is that there is no such control, and the execution of this task can be completed before the end of its execution. See the example:

public async Task EnviarEmailAsync()
{
    // ação para envio do email
    // normalmente é demorado, leva mais que 100ms por exemplo.
    return;
}

To consume, we do:

await EnviarEmailAsync();
return;

This will ensure that your code will wait for sending the email before returning.

Now using an example without returning a Task:

public async void EnviarEmailAsync()
{
    // ação para envio do email
    // normalmente é demorado, leva mais que 100ms por exemplo.
    return;
}

To consume, we do:

EnviarEmailAsync();
return;

In this case, upon returning, the Task - that exists, but just hasn’t been returning, and there are no references to it - will be canceled.

You can test this in this example in . NET Fiddle.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        Task.Run(async () =>
        {
            Console.WriteLine("Inicio de envio de emails.");
            await EnviarEmailAsync();
            EnviarEmail();      

            Console.WriteLine("Fim de execução.");
        }).Wait();
    }

    public static async Task EnviarEmailAsync()
    {
        await Task.Run(() => Thread.Sleep(500)); // simula envio de email, que dure 500ms       
        Console.WriteLine("Email A enviado.");
    }

    public static async void EnviarEmail()
    {
        await Task.Run(() => Thread.Sleep(500)); // simula envio de email, que dure 500ms       
        Console.WriteLine("Email B enviado.");
    }
}

The result will be:

> Inicio de envio de emails.
> Email A enviado.
> Fim de execução.

There will be no return of the method async void, because he had his cancellation forced by the end of his "summoner" - the method Main().

8

I don’t know give many details without researching further, but everyone considers it a mistake to exist the return void in a method async. There is a different way to deal with exceptions that causes problems in the application, so the pragmatic answer to the title question is never.

If you want to insist on that know that the application will not wait until the end to continue from there and in few cases this is interesting.

Behold blog about this. Has other article. And the recent article by Raymond Chen.

1

In addition to the answers:

Asynchronous methods that do not return Task or a Task<T> are dangerous by their "strange" control of exceptions in their execution. You have no way to monitor the life of this method, the end of it. It is a fire and Forget, shoot and forget.

Those exceptions that are swallowed up in methods async void are fired and can be seen by creating a Handler for any of those events that capture all untreated exceptions of the application as the TaskScheduler.UnobservedTaskException and the AppDomain.UnhandledException.

As stated in the above answers, and confirming with a good source: an author of MSDN Magazine confirms that we must ALWAYS return Task or Task<T> in asynchronous methods, even if we do not have to wait for the execution of the same.

The only exception to use async void sane handlers of events, such as the click of a button. But still, every care is necessary, in a case where you use the Handler parameters of the event, you should avoid the async void, since the execution flow does not wait for its end.

private void MyButton_Click(object sender, RoutedEventArgs e) { ... }

Some interesting discussions on the subject:

Browser other questions tagged

You are not signed in. Login or sign up in order to post.