AsnycLocal與ThreadLocal AsnyncLocal與ThreadLocal都是存儲線程上下文的變數,但是,在實際使用過程中兩者又有區別主要的表現在: AsyncLocal變數可以在父子線程中傳遞,創建子線程時父線程會將自己的AsyncLocal類型的上下文變數賦值到子線程中,但是, ...
AsnycLocal與ThreadLocal
AsnyncLocal與ThreadLocal都是存儲線程上下文的變數,但是,在實際使用過程中兩者又有區別主要的表現在:
- AsyncLocal變數可以在父子線程中傳遞,創建子線程時父線程會將自己的AsyncLocal類型的上下文變數賦值到子線程中,但是,當子線程改變線程上下文中AsnycLocal變數值後,父線程不會同步改變。也就是說AsnycLocal變數只會影響他的子線程,不會影響他的父級線程。
- TreadLocal只是當前線程的上下文變數,不能在父子線程間同步。
using System;
using System.Threading;
using System.Threading.Tasks;
namespace await_aysnc
{
class Program
{
static ThreadLocal<int> ThreadObj = new ThreadLocal<int>();
static AsyncLocal<int> AsyncObj = new AsyncLocal<int>();
static void Main(string[] args)
{
AsyncObj.Value = 1;
ThreadObj.Value = 1;
Console.WriteLine($"Task執行前:AsyncObj= {AsyncObj.Value} ThreadObj= {ThreadObj.Value} ThreeadId = {Thread.CurrentThread.ManagedThreadId}");
Task.Run(async() =>
{
Console.WriteLine($"RunAsync非同步執行前:AsyncObj= {AsyncObj.Value} ThreadObj= {ThreadObj.Value} ThreeadId = {Thread.CurrentThread.ManagedThreadId}");
await RunAsync();
Console.WriteLine($"RunAsync非同步執行後:AsyncObj = {AsyncObj.Value} ThreadObj= {ThreadObj.Value} ThreeadId = {Thread.CurrentThread.ManagedThreadId}");
});
Console.WriteLine($"Task執行後:AsyncObj= {AsyncObj.Value} ThreadObj= {ThreadObj.Value} ThreeadId = {Thread.CurrentThread.ManagedThreadId}");
Console.Read();
}
static async Task RunAsync()
{
Console.WriteLine($"Delay非同步執行前:AsyncObj = {AsyncObj.Value} ThreadObj= {ThreadObj.Value} ThreeadId = {Thread.CurrentThread.ManagedThreadId} ");
AsyncObj.Value = 2;
ThreadObj.Value = 2;
await Task.Delay(100);
Console.WriteLine($"Delay非同步執行後:AsyncObj = {AsyncObj.Value} ThreadObj= {ThreadObj.Value} ThreeadId = {Thread.CurrentThread.ManagedThreadId}");
}
}
}
Task執行前:AsyncObj= 1 ThreadObj= 1 ThreeadId = 1
Task執行後:AsyncObj= 1 ThreadObj= 1 ThreeadId = 1
RunAsync非同步執行前:AsyncObj= 1 ThreadObj= 0 ThreeadId = 3
Delay非同步執行前:AsyncObj = 1 ThreadObj= 0 ThreeadId = 3
Delay非同步執行後:AsyncObj = 2 ThreadObj= 0 ThreeadId = 4
RunAsync非同步執行後:AsyncObj = 1 ThreadObj= 0 ThreeadId = 4
從結果上可以看出一下結論:
- RunAsync執行前ThreadLocal值被切成0即ThreadLocal變數在新線程裡面沒有繼承主線程的上下文變數,但是AsyncLocal繼承了。
- Delay返回後,線程id變了,同時,TheadLocal中的變數為0。
- RunAsync結束後AyncLocal又切回主線程的上下文值,,同樣Threadlocal中的值丟失。
- 由於await執行完返回之後,.net會線上程池中隨機選取一個線程來執行await之後的邏輯,所以,await之後同時也會有一定幾率獲取到之前的線程,如果出現這種情形,TreadLocal會獲取到之前的上下文,此時會出現意料之外的問題,從現象上看報錯可能會是一個概率性問題。