0

Could someone please let me know when do we use one over the other with the below two implementations:

  1. await Task.Run(async () => Method());

  2. await Task.Run(() => Method());

What is the purpose for using async within the Task.Run() call?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Aryan M
  • 571
  • 3
  • 12
  • 33
  • 1
    Should 1 be `await Task.Run(async () => await Method());`? – ProgrammingLlama Dec 17 '18 at 01:18
  • 2
    If you have case 1, then @John is correct, except it can be simplified to `await Method()` – Nathan Werry Dec 17 '18 at 01:19
  • Assuming `Method` returns a Task, 1/ has no benefit over 2/ and has a slight overhead due to the allocation of the state machine – Kevin Gosse Dec 17 '18 at 07:36
  • @NathanWerry Not necessarily. If the method blocks the thread for a significant amount of time before yielding, it can be legitimate to run it in a separate thread (for instance, to avoid blocking the UI) – Kevin Gosse Dec 17 '18 at 07:38
  • @KevinGosse, I was expanding on what John commented, in which he has a function which is async, so yes, that assumption was there, but probably should have been mentioned. Also, it is running in a separate thread. The function is already using the async/await pattern, therefore we can just write the await, instead of wrapping an asynchronous task in an asynchronous task. – Nathan Werry Dec 17 '18 at 13:25

2 Answers2

2

There is no real reason to use #1. The point of using Task.Run is to make a long running task or I/O intensive unit of work and make it asynchronous, and since #1 is already asynchronous, the async anonymous function inside of the Task.Run is redundant and unnecessary.

Either you do the following to convert a unit of work to asynchronous:

await Task.Run(() => Method());
public void Method() 
{ 
    //doing intensive work here
}

Or you just await the already asynchronous unit of work.

await MethodAsync();
public async Task MethodAsync()
{
    //doing async work here
}
Nathan Werry
  • 876
  • 7
  • 18
  • Task.Run is to wrap a CPU-intensive unit of work as it will wrap it in a thread-based task. I/O stuff can usually be made asynchronous without the need of threads (instead using events), which in turn means that I/O-intensive unit of works shouldn’t be wrapped in Task.Run because you would waste a thread for nothing to gain. But in general you are right that wrapping a task in Task.Run is redundant. The only scenario where it would make sense to wrap a task in Task.Run is if the task is an I/O-bound task, but _also_ makes heavy computations as there wouldn’t be a thread for them to be async. – ckuri Dec 17 '18 at 07:37
  • Are you sure about that? The documentation for async includes multiple mentions of file reading and writing. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/ – Nathan Werry Dec 17 '18 at 13:32
  • Yes, file reading/writing is an I/O-bound task which doesn't need to be wrapped in a Task.Run, which is what my first part was about. My second part was about some hypothetical `EncryptAsync(string fileName)` function which returns a task because it uses async file functions. However in this case the encryption may be computationally expensive, but would still run on the calling main (UI) thread because async I/O functions often don't use threads for async. In this case it would make sense to wrap EncryptAsync in a Task.Run to make the encryption part run on a separate thread. – ckuri Dec 17 '18 at 18:45
-4

If the method you are calling is async you can use the async/await in the function.

async Task MainAsync()
{
   await Task.Run(async () => await MethodAsync());
   await Task.Run(() => Method());
}
async Task MethodAsync() { ... }
void Method() { ... }
thilinab
  • 117
  • 2
  • 8