tvr
tvr

Reputation: 4575

Is await with Task.Run (NonAsyncMethod()) any better?

Let us say, I have a call like this:

await Task.Run(async() => SomeLongRunningNonAsyncMethod());

My understanding is when SomeLongRunningNonAsyncMethod() is called, the call doesn't return until it encounters await. But there is no await in SomeLongRunningNonAsyncMethod().

So, is this same as direct SomeLongRunningNonAsyncMethod() call?

Upvotes: 0

Views: 187

Answers (3)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149618

My understanding is when SomeLongRunningNonAsyncMethod() is called, the call doesn't return until it encounters await. But there is no await in SomeLongRunningNonAsyncMethod().

You need to distinguish between the delegate you pass to Task.Run and the actual execution of Task.Run

The former will execute synchronously inside a ThreadPool thread. You dont need to use the async keyword as you are not awaiting on any async operation inside the given delegate.

The latter will hit its await when Task.Run begins to execute and yield control back to the calling method until the delegate finishes execution.

So, is this same as direct SomeLongRunningNonAsyncMethod() call?

No. A direct call would execute synchronously on the current running thread. Your code executes the delegate synchronously on a ThreadPool thread, meanwhile the thread the call to Task.Run awaits the completion of the Task in a non-blocking fashion.

Your code should actually be:

await Task.Run(SomeLongRunningNonAsyncMethod);

Upvotes: 3

Fredrik Mörk
Fredrik Mörk

Reputation: 158379

The awaitkeyword will cause control to be returned to the calling method as soon as the call to Task.Run returns. That call returns "immediately" (it will only schedule the operation using the current task scheduler, not wait for it to complete). Once the task is completed, the code following the await line will continue executing.

Upvotes: 0

Luaan
Luaan

Reputation: 63772

Your understanding is indeed flawed.

As the code execution gets to the await Task.Run, it will first execute Task.Run as usual (which will queue the method on the thread pool), and then return immediately. When the method inside the Task.Run finishes, the execution will continue after the await.

Whether this is useful or not depends heavily on your context. For example, if you're calling this from an event handler in a WinForms / WPF application, this is indeed a good way to avoid blocking the UI thread while doing some background work. If you're doing this in a web application, you're just causing a thread switch and a thread pool thread for no reason.

If you're doing I/O in the Task.Run, rather than CPU work, you want to find an asynchronous API to do the same I/O work - this will save you the thread that would block anyway while the I/O request completes.

Upvotes: 2

Related Questions