2

I have an async method M1Async. I need to call it in the constructor of a class. At first, I just call the async method and let it run

M1Async();

It runs and did the work as I expected - it's fine it runs in the background and populates the Winforms controls. However, Visual Studio shows a green line under the call and suggest me to insert an await in front of the function.

Warning CS4014 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.

So I changed the invoking the async method without await to

Task.Run(M1Async);

Now the warning is gone.

Are they actually the same? Since the latter one doesn't have the warning, is it the better way to call it?

ca9163d9
  • 27,283
  • 64
  • 210
  • 413
  • `await M1Async()` means: *Do M1Async but do not do the next line of code unless `M1Async` is done and returned from.* No `await` means don't wait for it to return, simply call `M1Async` and move to the next line of code to execute. – CodingYoshi Feb 11 '19 at 22:21
  • Yes, I don't need to await in the context. The question is comparing `M1async()` to `Task.Run(M1Async)` – ca9163d9 Feb 11 '19 at 22:23
  • 1
    There is no need to do `Task.Run(M1Async);`, just do `var _ = M1Async();` to get rid of warning. – JohanP Feb 11 '19 at 22:25
  • `Because this call is not awaited, execution of the current method continues before the call is completed.` It warned you about something that you may not want. But, you do want it. So disable the warning with a pragma, and move on. `and populates the Winforms controls` It makes me a little worried that you are populating controls in a background thread, but hey I assume you have tested it. – mjwills Feb 11 '19 at 22:33
  • 2
    Using `Task.Run` spins up a new thread unnecessarily (i.e. there is a considerable performance cost). It is not a good solution. – mjwills Feb 11 '19 at 22:34
  • @mjwills And where is an async method executed if you call it without await? Still in a thread from the thread pool, right, just as when you call Task.Run? – GolezTrol Feb 11 '19 at 22:37
  • 1
    `Task.Run` adds **another** one @GolezTrol. If you like that, why stop at one? Why not `Task.Run(Task.Run(Task.Run(Task.Run(` etc etc? ;) _And that is putting aside the fact that the async method may not use an extra thread, but that is not particularly relevant - the point I am making is that the `Task.Run` is 100%, definitely, unequivocally unnecessary in this context for the OP._ – mjwills Feb 11 '19 at 22:47
  • 3
    @GolezTrol What the underlying asynchronous operation is actually doing, we have no idea. But without `Task.Run` whatever work it does before getting to the asynchronous operation is run on the current thread, as opposed to taking the time to schedule that (not at all long running) operation in a thread pool thread. The underlying asynchronous operation may use another thread, or it may be a non-CPU bound asynchronous operation. – Servy Feb 11 '19 at 22:50
  • @mjwills, [there](https://stackoverflow.com/questions/22629951/suppressing-warning-cs4014-because-this-call-is-not-awaited-execution-of-the) I *deliberately* needed a fire-and-forget task (being aware of all its pitfalls, like exception handling, unobserved results etc). Here, it feels like the OP may actually need to keep track of the task, as suggested in Simonare answer below. The OP doesn't mention fire-and-forget. Does the state of the object he constructs further depend on that task? What if that task fails? He doesn't mention anything about that. – noseratio Feb 11 '19 at 23:01

1 Answers1

1

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;
}
Derviş Kayımbaşıoğlu
  • 28,492
  • 4
  • 50
  • 72