0

I'm currently getting into the async/await keywords, and went through the following questions: When correctly use Task.Run and when just async-await and Async/Await vs Threads

However even the second link doesn't answer my question, which is when to simply use

Task.Run(...)

versus

await Task.Run(...)

Is it situational or is there something to be gained by using await (and thus returning to the caller)?

Community
  • 1
  • 1
Iason
  • 209
  • 3
  • 11
  • 38
  • 5
    Like any other use of Task, not awaiting will result in the task being fired off and execution of the current method continuing immediately, while awaiting will return a task and wire up the rest of the method as a continuation (effectively halting execution of the current method until the task completes). What are you trying to achieve? – Ant P Mar 27 '17 at 11:46
  • @AntP Since I'm new to these keywords, I'm only trying to understand whether it is considered good practice to be using await for creating background threads, instead of firing them up directly, OR if using await Task.Run(...) is more situational, and then, in what context should I do it? – Iason Mar 27 '17 at 11:51
  • The two things produce different behaviours, so it is situational - if you want to return an incomplete `Task` that can be waited on further up the stack (e.g. to attach additional continuations, handle failures...), you will need to await (or return) the task that is returned by `Task.Run`. If you want to fire off the task and forget about it, you don't want to await it. – Ant P Mar 27 '17 at 11:53
  • @AntP Right, "If you want to fire off the task and forget about it, you don't want to await it" that makes more sense now – Iason Mar 27 '17 at 11:55

2 Answers2

4

The code Task.Run(...) (in both examples) sends a delegate to the thread pool and returns a task that will contain the results of that delegate. These "results" can be an actual return value, or it can be an exception. You can use the returned task to detect when the results are available (i.e., when the delegate has completed).

So, you should make use of the Task if any of the following are true:

  • You need to detect when the operation completed and respond in some way.
  • You need to know if the operation completed successfully.
  • You need to handle exceptions from the operation.
  • You need to do something with the return value of the operation.

If your calling code needs to do any of those, then use await:

await Task.Run(...);

With long-running background tasks, sometimes you want to do those (e.g., detect exceptions), but you don't want to do it right away; in this case, just save the Task and then await it at some other point in your application:

this.myBackgroundTask = Task.Run(...);

If you don't need any of the above, then you can do a "fire and forget", as such:

var _ = Task.Run(...); // or just "Task.Run(...);"

Note that true "fire and forget" applications are extremely rare. It's literally saying "run this code, but I don't care whether it completes, when it completes, or whether it was successful".

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

You can use Task.Run() when handling logic with fire and forget type, similar to invoking events if someone is subscribed to them. You can use this for logging, notifying, etc.

If you depend of the result or actions executed in your method, you need to use await Task.Run() as it pauses current execution until your task is finished.

Ognjen Babic
  • 727
  • 1
  • 4
  • 14