0

Let's say I have a function Task UploadAsync(Stream stream) upload some data to remote machine. Calling this function will make async keyword spread whole calling tree. Another way is to wrap it in Task.Run, kind of Fire and forgot way:

void DoUpload(Stream stream) {Task.Run(async () => await UploadAsync(stream)})}

I read from Stephen Cleary's blog says that Task.Run should only use for CPU bound operations, obviously uploading a chunk of data is not CPU bound. So here if I call await UploadAsync(stream) inside Task.Run seems a wrong way.

So my question is, is it a bad practice to use Task.Run to wrap and call async function ?

codewarrior
  • 723
  • 7
  • 22
  • do you want to wait when ```UploadAsync(stream)``` is finished? BTW, ```Task.Run``` will return ```Task```, and ```UploadAsync(stream)``` - will return ```Task```. So, what is difference for you?Why you need ```Task.Run``` at all? – tym32167 Jul 21 '17 at 08:13
  • Do you want to run it asynchronosly and forget about it or do you want to wait until the Task is finished? In the later case, just call `Task task = UploadAsync(stream)` and then `task.Wait()` to wait for it to finish. – Adwaenyth Jul 21 '17 at 08:18
  • `Another way is to wrap it in Task.Run, kind of Fire and forgot way:` There's no reason at all to wrap the code in `Task.Run` if you *actually* want to just fire it and forget it. That's adding lots of overhead for nothing in return. That said, it's almost certainly wrong to fire and forget something like that in the first place. – Servy Jul 21 '17 at 13:52
  • 1
    _"is it a bad practice to use Task.Run to wrap and call async function ?"_ -- what constitutes "bad practice" is primarily a matter of opinion. I agree with other comments, it's pointless in your scenario. But is it _harmful_ or _wrong_? That is at best dependent on context you haven't provided, and in most cases, just a matter of opinion. After all, if you're going to have the `Task.Run()` task ignore the returned task, you might as well just ignore it yourself (which is easy enough). – Peter Duniho Jul 21 '17 at 21:22

2 Answers2

1

Calling this function will make async keyword spread whole calling tree.

Yes, that's the point of asynchronous code. If you call an asynchronous function synchronously, then it's not asynchronous.

The best solution is to embrace asynchronous code, and call it with await. If, for some reason, this is not viable, then you can use one of the hacks in my brownfield async article. Note that there is no hack that works in every scenario.

For example, you can use the Thread Pool Hack:

Task.Run(() => UploadAsync(stream)).GetAwaiter().GetResult();

This wraps the asynchronous code into a background thread (avoiding deadlock problems, but also preventing the asynchronous code from using the calling context), and blocks waiting for the result (using GetAwaiter().GetResult() instead of Wait()/Result to avoid the AggregateException wrapper in the error case).

However, note that exposing a synchronous wrapper for asynchronous methods is an antipattern. So it would be a poor design to provide an Upload method that is implemented this way.

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

Task.Run(async () => await UploadAsync(stream)}) will return a Task that you'd need to await if you care about waiting for it to finish. Calling an async method within Task.Run makes no sense.

You could call .Wait() on the task, which will block the thread until the request is finished.

Async calls do have a tendency to 'infect' the whole call tree but I've yet to find any decent way to avoid that.

Fermin
  • 34,961
  • 21
  • 83
  • 129