diff --git a/aspnetcore/performance/performance-best-practices.md b/aspnetcore/performance/performance-best-practices.md index 5be7862d8b..d0b2e88f6b 100644 --- a/aspnetcore/performance/performance-best-practices.md +++ b/aspnetcore/performance/performance-best-practices.md @@ -32,11 +32,12 @@ A common performance problem in ASP.NET Core apps is blocking calls that could b * Block asynchronous execution by calling [Task.Wait](/dotnet/api/system.threading.tasks.task.wait) or [Task.Result](/dotnet/api/system.threading.tasks.task-1.result). * Acquire locks in common code paths. ASP.NET Core apps are most performant when architected to run code in parallel. +* Call [Task.Run](/dotnet/api/system.threading.tasks.task.run) and immediately await it. ASP.NET Core already runs app code on normal Thread Pool threads, so calling Task.Run only results in extra unnecessary Thread Pool scheduling. Even if the scheduled code would block a thread, Task.Run does not prevent that. **Do**: * Make [hot code paths](#understand-hot-code-paths) asynchronous. -* Call data access and long-running operations APIs asynchronously. +* Call data access and long-running operations APIs asynchronously if an asynchronous API is available. Once again, do not use [Task.Run](/dotnet/api/system.threading.tasks.task.run) to make a synchronus API asynchronous. * Make controller/Razor Page actions asynchronous. The entire call stack is asynchronous in order to benefit from [async/await](/dotnet/csharp/programming-guide/concepts/async/) patterns. A profiler, such as [PerfView](https://github.com/Microsoft/perfview), can be used to find threads frequently added to the [Thread Pool](/windows/desktop/procthread/thread-pools). The `Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start` event indicates a thread added to the thread pool.