Task.Run schedules synchronous or asynchronous work on a thread-pool thread and returns a Task that represents completion. It provides an async/await-friendly alternative to ThreadPool.QueueUserWorkItem, while the thread pool manages thread creation and reuse. section 4.1.3
Use Task.Run deliberately:
- Create multiple tasks and await Task.WhenAll when independent work should finish together. section 4.1.3
- Avoid awaiting Task.Run merely to continue sequentially; doing so adds task-management overhead without a benefit. section 4.1.3
- Prefer asynchronous I/O directly for file operations; wrapping blocking I/O in Task.Run consumes thread-pool threads while they wait. section 5.1
- Limit large bursts of work because excessive thread-pool use can delay unrelated work, including ASP.NET requests. section 8.1.2
- Copy loop variables before capturing them in lambdas, or every task may observe the loop's final value. section 5.1
Keeping a UI responsive
A long calculation can freeze a native UI when it runs on the UI thread. Run the calculation with Task.Run, await it from the event handler, and update the control afterward; await resumes on the UI thread in this case. section 5.4
Listing 4.8 Waiting for tasks to finish with Task.Run
public async Task RunInBackground()
{
var tasks = new Task[10];
for(int i=0;i<10;++i)
{
tasks[i] = Task.Run(RunInPool); #1
}
await Task.WhenAll(tasks); #2
Console.WriteLine("All finished");
}
private void RunInPool()
{
Console.WriteLine("Do stuff");
}
See the complete pattern for launching ten thread-pool tasks and awaiting their collective completion with Task.WhenAll. section 4.1.3
