I have had to replace the usage of ThreadLocal in my code with AsyncLocal so that the 'ambient state' is maintained when awaiting async operations.
However, an annoying behaviour of AsyncLocal is that it is 'flowed' to child threads. This is different to ThreadLocal. Is there any way to prevent this?
class Program
{
private static readonly ThreadLocal<string> ThreadState = new ThreadLocal<string>();
private static readonly AsyncLocal<string> AsyncState = new AsyncLocal<string>();
static async Task MainAsync()
{
ThreadState.Value = "thread";
AsyncState.Value = "async";
await Task.Yield();
WriteLine("After await: " + ThreadState.Value);
WriteLine("After await: " + AsyncState.Value); // <- I want this behaviour
Task.Run(() => WriteLine("Inside child task: " + ThreadState.Value)).Wait(); // <- I want this behaviour
Task.Run(() => WriteLine("Inside child task: " + AsyncState.Value)).Wait();
The AsyncLocal<T> class also provides optional notifications when the value associated with the current thread changes, either because it was explicitly changed by setting the Value property, or implicitly changed when the thread encountered an await or other context transition.
This type is thread-safe for all members.
Thread Local Storage is used to store thread-specific pieces of data. Thread-local storage (TLS) is a computer programming method that uses static or global memory local to a thread. All threads of a process share the virtual address space of the process.
If you need ambient data local to the asynchronous control flow, for example to cache WCF communication channels, use AsyncLocal instead of ThreadStaticAttribute or ThreadLocal provided by .NET 4.6 or the Core CLR. Some things just stick in our minds. When the world around us evolves, those things might no longer be true.
What is AsyncLocal < T >? AsyncLocal < T > is an object introduced after. Net 4.6, which accepts a generic parameter. Its main function is to save the value of a variable shared in the asynchronous waiting context. The asynchronous method is Task-based automatic thread scheduling, which may lead to data loss during asynchronous context switching.
The AsyncLocal<T> class also provides optional notifications when the value associated with the current thread changes, either because it was explicitly changed by setting the Value property, or implicitly changed when the thread encountered an await or other context transition.
In the example above, the Worker class has a ThreadLocal variable internally which creates a new instance of Validator for each Thread accessing it. The Worker implementation uses the current threading ambient context as a ThreadLocal.
AsyncLocal
stores the data in the execution context, which is automatically flown by most APIs (including Task.Run
).
One way to prevent that is to explicitly suppress flow whenever needed:
using (ExecutionContext.SuppressFlow())
{
Task.Run(...);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With