Interview frequency: …
Short answer
ThreadLocal associates its value with the current operating-system thread and loses context when execution switches threads after await, while AsyncLocal flows with the logical execution context across await threads.
Explanation
In asynchronous code, execution after await often resumes on a different ThreadPool thread. If you store a request or user ID in ThreadLocal, you may lose the value or read another thread's value at the first await. AsyncLocal<T> was designed to flow with ExecutionContext, keeping the logical value with async code as it moves between threads.
Code example
private static readonly AsyncLocal<string> _traceId = new();
public async Task Process() {
_traceId.Value = Guid.NewGuid().ToString();
await Task.Delay(100); // Execution may resume on an entirely different thread
Console.WriteLine(_traceId.Value); // The value remains precisely preserved
}Common mistakes
- Using ThreadLocal to store HTTP request context in modern asynchronous web servers.
Follow-up questions
- How do you process asynchronous work in parallel with Parallel.ForEachAsync in .NET 6+?
- How does System.Threading.Channels work, and what does it offer for the Producer-Consumer pattern?