Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about calling CPU-bound methods synchronously from an async method

I'm getting my feet wet with .NET 4.5's async/await construct. I'm working on a RESTful Web API solution. I'm trying to figure out what to do with CPU-bound operation - 1) call it synchronously from the current thread, or 2) use Task.Run()?

Let's use the example from this page:

async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoCPUBoundWork();

    // The await operator suspends AccessTheWebAsync. 
    //  - AccessTheWebAsync can't continue until getStringTask is complete. 
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
    //  - Control resumes here when getStringTask is complete.  
    //  - The await operator then retrieves the string result from getStringTask. 
    string urlContents = await getStringTask;

    // The return statement specifies an integer result. 
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    return urlContents.Length;
}

Here, let's suppose DoCPUBoundWork() is strictly CPU-bound and involves no IO of any kind.

Is it the best practice to call it from the current thread as shown?

Or is it better to have the following?

await Task.Run(() => DoCPUBoundWork()).ConfigureAwait(false);

I've read up on some of Mr. Cleary's posts, and am getting some mixed suggestions. In this post, he suggests that it's better to call the CPU-bound stuff synchronously to avoid the unnecessary overhead of async/await/Task.Run(). However, in this post, he suggests to use Task.Run() for CPU-bound operations without mentioning any exception cases. I'm sure I'm missing something obvious. Hoping to get some clarification on this.

like image 608
Zoomzoom Avatar asked May 22 '15 18:05

Zoomzoom


1 Answers

Is it the best practice to call it from the current thread as shown?

If your current thread is free while the async operating is on going, why use a different thread? What would make that thread better than the one you're already using?

Question comes to mind concerning what DoIndependentWork is actually doing. If it's vital that it completes before the HTTP request finishes, I would invoke it synchronously. If the work isn't vital to complete before the HTTP request completes, than I would look for an entirely different solution. Using Task.Run is dangerous in ASP.NET.

Remember that continuations in ASP.NET run on arbitrary thread pool threads.

like image 184
Yuval Itzchakov Avatar answered Oct 18 '22 01:10

Yuval Itzchakov