When does not return Task in async methods?

14

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

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

However, in what situations do I not necessarily need to return a Task ?

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

What is the difference and the impact of declaring the two methods above?

    
asked by anonymous 11.07.2017 / 04:02

3 answers

13

Every method async should instead return a Task - regardless of whether or not it will wait for its end.

A async method - in addition to the obviousness of being an asynchronous method - means that a new Thread will be created to perform its action. And for you to have control over the lifecycle of that task, your method returns a type Task so you can know when this task is finished, whether you want to end its execution or even to know what it has returned. / p>

The problem of creating a async void method is that this control does not exist, and the execution of that task may be terminated 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 the email to be sent 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, when returning, the Task - that exists, but only did not return, 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.

It will not return the async void method, as it has been forced to terminate at the end of its "invocator" - the Main() method.

    
11.07.2017 / 10:52
7

I do not know how to give too many details without searching more, but everyone thinks it's wrong to have the void return in a async method. There is a different way to handle exceptions that causes problems in the application, so the pragmatic answer to the title question is never .

If you want to insist on this, know that the application will not wait for the termination to continue and in a few cases this is interesting.

See blog about this . You have another article . And the recent Raymond Chen article .

    
11.07.2017 / 06:35
0

In addition to the answers:

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

These exceptions that are swallowed in async void methods are raised and can be seen by creating a handler for any of these events that catch all unhandled exceptions of the application such as TaskScheduler.UnobservedTaskException and AppDomain.UnhandledException .

As stated in the answers above, and confirming with a good source: an author of MSDN Magazine confirms

a> that we should ALWAYS return Task or Task<T> in asynchronous methods, even though we do not have to wait for it to execute.

The only exception to use async void are handlers of events, such as the click of a button. But still, all care is needed, in case you use the event handler parameters, you should avoid async void , since the execution stream does not wait for its completion.

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

Some interesting discussions on the subject:

03.08.2017 / 21:05