Issue
I have read these articles:
ASP.NET Core Performance Best Practices
When should I use Task.Run in Asp.Net Core?
Is it allowed to use Task.Run in an ASP.NET Core controller?
In the first article in docs.microsoft
we can see this statement:
Call data access, I/O, and long-running operations APIs asynchronously
if an asynchronous API is available. Do not use Task.Run to make a
synchronous API asynchronous.
I don’t understand this statement well. I’m confused about where and when I should use Task.Run
and where and when I should (can) write async web API. For example, consider this method:
public int DoSomeHeavyWork()
{
// Consider heavy computations
int i = 10;
i = i * 2;
i = i + 4;
return i;
}
and this method:
public void SaveSomthingInDb(Order ord)
{
_dbContext.Orders.Add(ord);
_dbContext.SaveChange();
}
according to the above statement, I should write a web method synchronously because there is no async
version:
public IActionResult API_DoSomeHeavyWork()
{
return Ok(DoSomeHeavyWork());
}
but for method 2 I can change it this way:
public async Task SaveSomthingInDbAsync(Order ord)
{
_dbContext.Orders.Add(ord);
await _dbContext.SaveChangeAsync();
}
so I can write an API for that like this:
public async Task<IActionResult> API_SaveSomthingInDbAsync(Order ord)
{
await SaveSomthingInDbAsync(ord);
return Ok("Object Added");
}
I don’t know هs my perception of this issue is correct or not? Are write these methods true? Is there any way to run the first API async
?
Thanks
Edit 1)
Thanks to "Stephen Cleary".
If we assume this sentence: We use async
method in web methods of Web API to prevent blocking thread pool threads and take more requests…
Please consider this code:
await _context.Order.ToListAsync();
according to this code, there is an assembly named Microsoft.EntityFrameworkCore
and it has a async
method named ToListAsync
:
public static Task<List<TSource>> ToListAsync<TSource>(this IQueryable<TSource> source, CancellationToken cancellationToken = default(CancellationToken))
First question is how ToListAsync
implemented? Is it implemented like this?
public static Task<List<TSource>> ToListAsync<TSource>(...)
{
Task.Run(()=>{ <Some thing>.ToList() });
}
Second question is if the method DoSomeHeavyWork
placed in a separate assembly and rewrite it this way:
public Task<int> DoSomeHeavyWork()
{
Task.Run(() =>
{
// Consider heavy computations
int i = 10;
i = i * 2;
i = i + 4;
return i;
}
}
Can I then call it async
from my web API and free thread pool thread?
Thanks
Solution
I’m confused about where and when I should use Task.Run
On ASP.NET, almost never. You can adopt "never" as a general rule.
and where and when I should (can) write async web API.
Your controller actions should be asynchronous if and only if they invoke asynchronous code. Generally speaking, you should prefer asynchronous APIs at the lowest level for all code that performs I/O. Then your action methods are asynchronous only if they need to call that asynchronous code.
I should write a web method synchronously because there is no async version … but for method 2 I can change it this way
Yup.
Is there any way to run the first API async?
Think of it this way: if there is synchronous (CPU-bound) work to do, then that work needs a thread. It’s already running on a thread pool thread (because web requests run on threads from thread
pool). Task.Run
will move that work to a different thread pool thread, but it will still run on a thread pool thread. So Task.Run
doesn’t help anything; it just adds overhead and provides no benefit. Hence the general rule of "don’t use Task.Run
on ASP.NET".
Answered By – Stephen Cleary
Answer Checked By – Clifford M. (BugsFixing Volunteer)