Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do you have to put Task.Run in a method to make it async?

I'm trying to understand async await in the simplest form. I want to create a very simple method that adds two numbers for the sake of this example, granted, it's no processing time at all, it's just a matter of formulating an example here.

Example 1

private async Task DoWork1Async() {     int result = 1 + 2; } 

Example 2

private async Task DoWork2Async() {     Task.Run( () =>     {         int result = 1 + 2;     }); } 

If I await DoWork1Async() will the code run synchronously or asynchronously?

Do I need to wrap the sync code with Task.Run to make the method awaitable AND asynchronous so as not to block the UI thread?

I'm trying to figure out if my method is a Task or returns Task<T> do I need to wrap the code with Task.Run to make it asynchronous.

Stupid question I'm sure but I see examples on the net where people are awaiting code that has nothing async within and not wrapped in a Task.Run or StartNew.

like image 578
Neal Avatar asked Jun 15 '13 00:06

Neal


People also ask

Is Task run asynchronous?

NET, Task. Run is used to asynchronously execute CPU-bound code.

Do you need to await Task run?

If you use Task. Run with an I/O operation, you're creating a thread (and probably occupying a CPU core) that will mostly be waiting. It may be a quick and easy way to keep your application responsive, but it's not the most efficient use of system resources. A much better approach is to use await without Task.

Can we use async without Task?

Implementing a method with the async keyword without using await raises a compiler warning. You could remove the async keyword and use "return Task.

How does async method work?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete.


1 Answers

First, let's clear up some terminology: "asynchronous" (async) means that it may yield control back to the calling thread before it starts. In an async method, those "yield" points are await expressions.

This is very different than the term "asynchronous", as (mis)used by the MSDN documentation for years to mean "executes on a background thread".

To futher confuse the issue, async is very different than "awaitable"; there are some async methods whose return types are not awaitable, and many methods returning awaitable types that are not async.

Enough about what they aren't; here's what they are:

  • The async keyword allows an asynchronous method (that is, it allows await expressions). async methods may return Task, Task<T>, or (if you must) void.
  • Any type that follows a certain pattern can be awaitable. The most common awaitable types are Task and Task<T>.

So, if we reformulate your question to "how can I run an operation on a background thread in a way that it's awaitable", the answer is to use Task.Run:

private Task<int> DoWorkAsync() // No async because the method does not need await {   return Task.Run(() =>   {     return 1 + 2;   }); } 

(But this pattern is a poor approach; see below).

But if your question is "how do I create an async method that can yield back to its caller instead of blocking", the answer is to declare the method async and use await for its "yielding" points:

private async Task<int> GetWebPageHtmlSizeAsync() {   var client = new HttpClient();   var html = await client.GetAsync("http://www.example.com/");   return html.Length; } 

So, the basic pattern of things is to have async code depend on "awaitables" in its await expressions. These "awaitables" can be other async methods or just regular methods returning awaitables. Regular methods returning Task/Task<T> can use Task.Run to execute code on a background thread, or (more commonly) they can use TaskCompletionSource<T> or one of its shortcuts (TaskFactory.FromAsync, Task.FromResult, etc). I don't recommend wrapping an entire method in Task.Run; synchronous methods should have synchronous signatures, and it should be left up to the consumer whether it should be wrapped in a Task.Run:

private int DoWork() {   return 1 + 2; }  private void MoreSynchronousProcessing() {   // Execute it directly (synchronously), since we are also a synchronous method.   var result = DoWork();   ... }  private async Task DoVariousThingsFromTheUIThreadAsync() {   // I have a bunch of async work to do, and I am executed on the UI thread.   var result = await Task.Run(() => DoWork());   ... } 

I have an async/await intro on my blog; at the end are some good followup resources. The MSDN docs for async are unusually good, too.

like image 148
Stephen Cleary Avatar answered Oct 06 '22 12:10

Stephen Cleary