Suppressing "Warning Cs4014: Because This Call Is Not Awaited, Execution of the Current Method Continues..."

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

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;
}

Suppressing warning CS4014: Because this call is not awaited, execution of the current method continues...

With C# 7 you can now use discards:

_ = WorkAsync();

How to solve warning CS4014: Call is not awaited

I would use some code like this to solve both problems:

public MainWindow()
{
this.Initialization = this.WaitingPort();
...
}

public Task Initialization { get; }

private async void Button_ClickOpen(object sender, RoutedEventArgs e)
{
await this.Initialization; // Do this in every public method and non-public if they're called out of an 'event'

var controllerPort = await this.ShowProgressAsync("Please wait", " ");
controllerPort.SetIndeterminate();
await Task.Run(async () =>
{
try
{
blabla
}
catch (Exception)
{
await WaitingPort();
}
}
}

This is the way that Stephen Cleary propagates.

Compiler warning CS4014 not emitted during build

The async modifier allows you to write code that returns a Task more conveniently (with await), but it has no representation in IL*. In a compiled assembly, the method simply looks like public static Task<string> DoSomething to the compiler, and calling those without awaiting their result doesn't trigger the warning (even if the methods live in the same assembly). Replace Class1.DoSomething with something else that returns a task and ought to be awaited (say Task.Delay(2000)) and you'll likewise see the compiler doesn't warn. When all of the source code is available, however, the compiler (and by compiler I mean Roslyn) can identify the method as async because the modifier is still part of the syntax tree.

So why doesn't the compiler just always warn when you call a method returning a Task without using the result, regardless of whether it happened to be written using async? Good question. While there are plenty of legitimate scenarios where you don't wait to await a Task (because you want to pass it to Task.WhenAll for example) all of these involve storing the Task somewhere else, which would not raise the warning. Calling a method that returns a Task and discarding the result entirely is almost certainly a mistake (and when it's intentional, there are elegant ways of suppressing the warning), which is why this warning exists in the first place.

I suspect the implementation of this warning could use a tweak (or a replacement with a new warning), but only the people working on the compiler would know that for sure.


*: this isn't actually true; async methods have an AsyncStateMachineAttribute applied to them for more convenient debugging. But, for whatever reason, the compiler doesn't use this to identify async methods across assemblies. Nor should it, arguably: there's nothing particularly special about async in terms of the Task the method returns. But if they wanted to preserve the stated semantics of CS4104 exactly (warn if the result of an async method is unused) this would be one way to do it.

Task.Run(M1Async) vs M1Async()?

when you use async method without await keyword, It is basically fire and forget. It means that you are not insterested with returning object or even the result of the operation (whether it is success or failure).

If you have intention to use output of this task inside another method, It is not guaranteed that the task operation is finished/will be finished and the value is available to be used.

If you look at the signature of Task.Run you will see that it returns task. From this we can conclude that if the Task.Run is not awaited it will be as before which is Fire and Forget

in your constructor you can do

private readonly Task _task;

MyConstructor()
{
_task = M1Async();
}

public async Task MyMethod()
{
//if the result of the async method is important
await _task;
}

Why do I get a warning when trying to run an async method on another thread?

TL;DR

The reason why you get the warning is because

 Task.Run(() => DoThings(10));   // warning here

returns a Task, and since your ServePage method is marked as async, the compiler believes that you should await the result of the Task

Detail

You're mixing two very different paradigms, which coincidentally both involve Task, viz:

  • Task.Run(), which is generally useful for parallelizing CPU bound work by utilizing multiple cores which may be available
  • async / await, which is useful for waiting for I/O bound operations to complete, without blocking (wasting) a thread.

So for instance, if you wanted to do 3 x CPU bound operations concurrently, and since Task.Run returns a Task, what you could do is:

public Page ServePage() // If we are CPU bound, there's no point decorating this as async
{
var taskX = Task.Run(() => CalculateMeaningOfLife()); // Start taskX
var taskY = Task.Run(() => CalculateJonSkeetsIQ()); // Start taskY
var z = DoMoreHeavyLiftingOnCurrentThread();
Task.WaitAll(taskX, taskY); // Wait for X and Y - the Task equivalent of `Thread.Join`

// Return a final object comprising data from the work done on all three tasks
return new Page(taskX.Result, taskY.Result, z);
}

The above is likely to utilise up to three threads, which could do the CPU bound work concurrently if there are sufficient cores to do so. Note however that using multiple threads concurrently will reduce the scalability of your system, since fewer simultaneous pages can be served without context switching.

This is in contrast to async / await, which is generally used to free up threads while waiting for I/O bound calls to complete. Async is commonly used in Api and Web apps to increase scalability as the thread is released for other work while the IO bound work happens.
Assuming DoThings is indeed I/O bound, we can do something like:

public async Task<string> DoThings(int foo) {
var result = await SomeAsyncIo(foo);
return "done!";
}

Async work can also be done in parallel:

public async Task<Page> ServePage() {
var task1 = DoThings(123); // Kick off Task 1
var task2 = DoThings(234); // Kick off Task 2 in parallel with task 1
await Task.WhenAll(task1, task2); // Wait for both tasks to finish, while releasing this thread
return new Page(task1.Result, task2.Result); // Return a result with data from both tasks
}

If the I/O bound work takes a reasonable amount of time, there's a good chance there's a point during the await Task.WhenAll when ZERO threads are actually running - See Stephen Cleary's article.

There's a 3rd, but very dangerous option, which is fire and forget. Since method DoThings is already marked as async, it already returns a Task, so there's no need at all to use Task.Run at all. Fire and forget would look as follows:

public Page ServePage() // No async
{
#pragma warning disable 4014 // warning is suppresed by the Pragma
DoThings(10); // Kick off DoThings but don't wait for it to complete.
#pragma warning enable 4014

// ... other code
return new Page();
}

As per @JohnWu's comment, the 'fire and forget' approach is dangerous and usually indicates a design smell. More on this here and here

Edit

Re:

there is nuance to this that escapes me over and over, such as that calling an async method that returns Task from a synchronous method fires-and-forgets execution of the method. (That's the very last code sample.) Am I understanding that correctly?

It's a bit difficult to explain, but irrespective of whether called with, or without the await keyword, any synchronous code in an invoked async method before the first await will be executed on the caller's thread, unless we resort to hammers like Task.Run.

Perhaps this example might help the understanding (note that we're deliberately using synchronous Thread.Sleep and not await Task.Delay to simulate CPU bound work and introduce latency which can be observed)

public async Task<Page> ServePage()
{
// Launched from this same thread,
// returns after ~2 seconds (i.e. hits both sleeps)
// continuation printed.
await DoThings(10);

#pragma warning disable 4014
// Launched from this same thread,
// returns after ~1 second (i.e. hits first sleep only)
// continuation not yet printed
DoThings(10);

// Task likely to be scheduled on a second thread
// will return within few milliseconds (i.e. not blocked by any sleeps)
Task.Run(() => DoThings(10));

// Task likely to be scheduled on a second thread
// will return after 2 seconds, although caller's thread will be released during the await
// Generally a waste of a thread unless also doing CPU bound work on current thread, or unless we want to release the calling thread.
await Task.Run(() => DoThings());

// Redundant state machine, returns after 2 seconds
// see return Task vs async return await Task https://stackoverflow.com/questions/19098143
await Task.Run(async () => await DoThings());
}

public async Task<string> DoThings(int foo) {
Thread.Sleep(1000);
var result = await SomeAsyncIo(foo);
Trace.WriteLine("Continuation!");
Thread.Sleep(1000);
return "done!";
}

There's one other important point to note - in most cases, there are no guarantees that the continuation code AFTER an await will be executed on the same thread as that before the await. The continuation code is re-written by the compiler into a Task, and the continuation task will be scheduled on the thread pool.

Compiler warning 'await' operator, should I ignore it?

add async to the method defintion

private async void CreateButton_Click(object sender, RoutedEventArgs e)

and add await to

await MsgDialog.ShowAsync();

What is the proper way to use Dispatcher.RunAsync() to start a task and return immediately?


Why is the compiler happy with this redundancy?

Because it uses a very simple heuristic. It doesn't do an in-depth analysis of the entire program to determine if every code path (or any code path) observes the results of the Task. The warning is only triggered by the return value of the Task-returning method (in an async method) not ever being stored or accessed. The main idea here is to prevent someone from calling a method that they don't even realize is asynchronous and unintentionally ignoring the result. Intentionally ignoring the result isn't something it's trying to prevent.



Related Topics



Leave a reply



Submit