ChatGPT解决这个技术问题 Extra ChatGPT

warning this call is not awaited, execution of the current method continues

Just got VS2012 and trying to get a handle on async.

Let's say I've got an method that fetches some value from a blocking source. I don't want caller of the method to block. I could write the method to take a callback which is invoked when the value arrives, but since I'm using C# 5, I decide to make the method async so callers don't have to deal with callbacks:

// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
    return Task.Factory.StartNew(() => {
        Console.Write(prompt);
        return Console.ReadLine();
    });
}

Here's an example method that calls it. If PromptForStringAsync wasn't async, this method would require nesting a callback within a callback. With async, I get to write my method in this very natural way:

public static async Task GetNameAsync()
{
    string firstname = await PromptForStringAsync("Enter your first name: ");
    Console.WriteLine("Welcome {0}.", firstname);

    string lastname = await PromptForStringAsync("Enter your last name: ");
    Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}

So far so good. The problem is when I call GetNameAsync:

public static void DoStuff()
{
    GetNameAsync();
    MainWorkOfApplicationIDontWantBlocked();
}

The whole point of GetNameAsync is that it's asynchronous. I don't want it to block, because I want to get back to the MainWorkOfApplicationIDontWantBlocked ASAP and let GetNameAsync do its thing in the background. However, calling it this way gives me a compiler warning on the GetNameAsync line:

Warning 1   Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

I'm perfectly aware that "execution of the current method continues before the call is completed". That's the point of asynchronous code, right?

I prefer my code to compile without warnings, but there's nothing to "fix" here because the code is doing exactly what I intend it to do. I can get rid of the warning by storing the return value of GetNameAsync:

public static void DoStuff()
{
    var result = GetNameAsync(); // supress warning
    MainWorkOfApplicationIDontWantBlocked();
}

But now I have superfluous code. Visual Studio seems to understand that I was forced to write this unnecessary code, because it suppresses the normal "value never used" warning.

I can also get rid of the warning by wrapping GetNameAsync in a method that's not async:

    public static Task GetNameWrapper()
    {
        return GetNameAsync();
    }

But that's even more superfluous code. So I have to write code I don't need or tolerate an unnecessary warning.

Is there something about my use of async that's wrong here?

BTW, when implementing PromptForStringAsync you do more work than you need to; just return the result of Task.Factory.StartNew. It's already a task who's value is the string entered in the console. There's no need to await it an return the result; doing so adds no new value.
Wwouldn't it make more sense for GetNameAsync to provide the full name that was provided by the user (i.e. Task<Name>, rather than just returning a Task? DoStuff could then store that task, and either await it after the other method, or even pass the task to that other method so it could await or Wait it somewhere inside of it's implementation.
@Servy: If I just return the Task, I get an error "Since this is an async method, the return expression must be of type 'string' rather than 'Task'".
Remove the async keyword.
IMO, this was a poor choice for a warning on the part of the C# team. Warnings should be for things which are almost certainly wrong. There are a lot of cases where you want to "fire-and-forget" an async method, and other times where you actually do want to await it.

C
Community

If you really don't need the result, you can simply change the GetNameAsync's signature to return void:

public static async void GetNameAsync()
{
    ...
}

Consider to see answer to a related question: What's the difference between returning void and returning a Task?

Update

If you need the result, you can change the GetNameAsync to return, say, Task<string>:

public static async Task<string> GetNameAsync()
{
    string firstname = await PromptForStringAsync("Enter your first name: ");
    string lastname = await PromptForStringAsync("Enter your last name: ");
    return firstname + lastname;
}

And use it as follows:

public static void DoStuff()
{
    Task<string> task = GetNameAsync();

    // Set up a continuation BEFORE MainWorkOfApplicationIDontWantBlocked
    Task anotherTask = task.ContinueWith(r => {
            Console.WriteLine(r.Result);
        });

    MainWorkOfApplicationIDontWantBlocked();

    // OR wait for the result AFTER
    string result = task.Result;
}

That would only be the case if he never cares about the result, as opposed to just not needing the result this one time.
@Servy, right, thanks for clarification. But OP's GetNameAsync doesn't return any value (except the result itself, of course).
Correct, but by returning a task he can know when it finishes executing all of the async operations. If it returns void, he has no way of knowing when it's done. That's what I meant when I said "the result" in my previous comment.
As a general rule, you should never have an async void method except for event handlers.
Another thing to note here is that behaviour is different when it comes to unobserved exceptions when you switch to async void any exception that you don't catch will crash your process, but in .net 4.5 it will keep running.
W
Willem

I'm quite late to this discussion, but there is also the option to use the #pragma pre-processor directive. I have some async code here and there that I explicitly do not want to await in some conditions, and I dislike warnings and unused variables just like the rest of you:

#pragma warning disable 4014
SomeMethodAsync();
#pragma warning restore 4014

The "4014" comes from this MSDN page: Compiler Warning (level 1) CS4014.

See also the warning/answer by @ryan-horath here https://stackoverflow.com/a/12145047/928483.

Exceptions thrown during an async call that is not awaited will be lost. To get rid of this warning, you should assign the Task return value of the async call to a variable. This ensures you have access to any exceptions thrown, which will be indicated in the return value.

Update for C# 7.0

C# 7.0 adds a new feature, discard variables: Discards - C# Guide, which can also help in this regard.

_ = SomeMethodAsync();

That's absolutely awesome. I had no idea you could do this. Thank you!
It is not even required to say var, just write _ = SomeMethodAsync();
Underline - just like in go - nice
Seems like this should be the one marked as the correct answer. The documentation for "Discards" explains it's usage for this type of scenario exactly.
J
Joe Savage

I'm not particularly fond of the solutions that either assign the task to an unused variable, or changing the method signature to return void. The former creates superfluous, non-intuitive code, while the latter may not be possible if you're implementing an interface or have another usage of the function where you want to use the returned Task.

My solution is to create an extension method of Task, called DoNotAwait() that does nothing. This will not only suppress all warnings, ReSharper or otherwise, but makes the code more understandable, and indicates to future maintainers of your code that you really intended for the call to not be awaited.

Extension method:

public static class TaskExtensions
{
    public static void DoNotAwait(this Task task) { }
}

Usage:

public static void DoStuff()
{
    GetNameAsync().DoNotAwait();
    MainWorkOfApplicationIDontWantBlocked();
}

Edited to add: this is similar to Jonathan Allen's solution where the extension method would start the task if not already started, but I prefer to have single-purpose functions so that the caller's intent is completely clear.


I like this but I renamed it to Unawait() ;)
p
pushkin

async void IS BAD!

What's the difference between returning void and returning a Task? https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

What I suggest is that you explicitly run the Task via an anonymous method...

e.g.

public static void DoStuff()
{
    Task.Run(async () => GetNameAsync());
    MainWorkOfApplicationIDontWantBlocked();
}

Or if you did want it to block you can await on the anonymous method

public static void DoStuff()
{
    Task.Run(async () => await GetNameAsync());
    MainWorkOfApplicationThatWillBeBlocked();
}

However, if your GetNameAsync method has to interact with UI or even anything UI bound, (WINRT/MVVM, I'm looking at you), then it gets a little funkier =)

You'll need to pass the reference to the UI dispatcher like this...

Task.Run(async () => await GetNameAsync(CoreApplication.MainView.CoreWindow.Dispatcher));

And then in your async method you'll need to interact with your UI or UI bound elements thought that dispatcher...

dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {  this.UserName = userName; });

Your Task extension is awesome. Don't know why I haven't implemented one before.
The first approach you mention causes a different warning: 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. This also causes a new thread to be created, whereas a new thread will not necessarily be created with async/await alone.
You should be up sir!
B
Baptiste Candellier

This is what I'm currently doing:

SomeAyncFunction().RunConcurrently();

Where RunConcurrently is defined as...

 /// <summary> 
 /// Runs the Task in a concurrent thread without waiting for it to complete. This will start the task if it is not already running. 
 /// </summary> 
 /// <param name="task">The task to run.</param> 
 /// <remarks>This is usually used to avoid warning messages about not waiting for the task to complete.</remarks> 
 public static void RunConcurrently(this Task task) 
 { 
     if (task == null) 
         throw new ArgumentNullException("task", "task is null."); 

     if (task.Status == TaskStatus.Created) 
         task.Start(); 
 } 

https://github.com/docevaad/Anchor/blob/master/Tortuga.Anchor/Tortuga.Anchor.source/shared/TaskUtilities.cs

https://www.nuget.org/packages/Tortuga.Anchor/


+1. This looks like it avoids all the problems being compared in the comments of other answers. Thanks.
You just need this: public static void Forget(this Task task) { }
what do you mean there @ShitalShah
@ShitalShah that will only work with auto-starting tasks such as those created with async Task. Some tasks need to be manually started.
d
devlord

According to the Microsoft article on this warning, you can solve it by simply assigning the returned task to a variable. Below is a translation of the code provided in the Microsoft example:

    // To suppress the warning without awaiting, you can assign the 
    // returned task to a variable. The assignment doesn't change how
    // the program runs. However, the recommended practice is always to
    // await a call to an async method.
    // Replace Call #1 with the following line.
    Task delayTask = CalledMethodAsync(delay);

Note that doing this will result in the "Local variable is never used" message in ReSharper.


Yes, that suppresses the warning, but no, that does not really solve anything. Task-returning functions should be await-ed unless you've got a very good reason not to. There is no reason here why discarding the task would be better than the already accepted answer of using an async void method.
I also prefer the void method. This makes StackOverflow smarter than Microsoft, but of course that should be a given.
async void introduces serious problems around error handling and results in un-testable code (see my MSDN article). It would be far better to use the variable -- if you're absolutely sure that you want exceptions silently swallowed. More likely, the op would want to start two Tasks and then do an await Task.WhenAll.
@StephenCleary Whether exceptions from unobserved tasks get ignored is configurable. If there is any chance your code will be used in someone else's project, don't let that happen. A simple async void DoNotWait(Task t) { await t; } helper method can be used to avoid the drawbacks of async void methods that you describe. (And I don't think Task.WhenAll is what the OP wants, but it very well could be.)
@hvd: Your helper method would make it testable, but it would still have very poor exception handling support.
J
JuanluElGuerre

Here, a simple solution.

public static class TasksExtensions
{
    public static void RunAndForget(this Task task)
    {
    }
}

Regards


G
Guffa

It's your simplified example that causes the superflous code. Normally you would want to use the data that was fetched from the blocking source at some point in the program, so you would want the result back so that it would be possible to get to the data.

If you really have something that happens totally isolated from the rest of the program, async would not be the right approach. Just start a new thread for that task.


I do want to use the data fetched from the blocking source, but I don't want to block the caller while I wait for it. Without async, you might accomplish this by passing in a callback. In my example, I have two asynchronous methods that need to be called in sequence, and the second call needs to use a value returned by the first. This would meaning nesting callback handlers, which gets ugly as hell. The documentation I've been reading suggests this is specifically what async was designed to clean up (for instance)
@Mud: Just send the result from the first async call as a parameter to the second call. That way the code in the second method starts right away, and it can wait for the result from the first call when it feels like it.
I can do that, but without async that means nested callbacks, like this: MethodWithCallback((result1) => { Use(result1); MethodWithCallback((result2) => { Use(result1,result2); }) Even in this trivial example, it's a bitch to parse. With async, equivalent code is generated for me when I write result1 = await AsyncMethod(); Use(result1); result2 = await AsyncMethod(); Use(result1,result2); Which is a lot easier to read (albeit neither are very readable smashed together in this comment!)
@Mud: Yes. But you can call the second async method right after the first, there is no reason for it to wait for the synchronous call to Use.
I really don't get what you're saying. MethodWithCallback is asynchronous. If I call them back to back without waiting on the first call, the second call may finish before the first. However, I need the result of the first call in the handler for the second. So I have to wait on the first call.
S
Simon Mourier

If you don't want to change the method signature to return void (as returning void should always be avoided), you can use C# 7.0+ Discard feature like this, which is slightly better than assigning to a variable (and should remove most other source validation tools warnings):

public static void DoStuff()
{
    _ = GetNameAsync(); // we don't need the return value (suppresses warning)
    MainWorkOfApplicationIDontWantBlocked();
}

C
Community

Do you really want to ignore the result? as in including ignoring any unexpected exceptions?

If not you might want a look at this question: Fire and Forget approach,