### 前言 在非同步編程中,處理非同步操作之間的數據流轉是一個比較常用的操作。`C#`非同步編程提供了一個強大的工具來解決這個問題,那就是`AsyncLocal`。它是一個線程本地存儲的機制,可以在非同步操作之間傳遞數據。它為我們提供了一種簡單而可靠的方式來共用數據,而不必擔心線程切換或非同步上下文的變化。 ...
前言
在非同步編程中,處理非同步操作之間的數據流轉是一個比較常用的操作。C#
非同步編程提供了一個強大的工具來解決這個問題,那就是AsyncLocal
。它是一個線程本地存儲的機制,可以在非同步操作之間傳遞數據。它為我們提供了一種簡單而可靠的方式來共用數據,而不必擔心線程切換或非同步上下文的變化。本文我們將探究AsyncLocal
的原理和用法,併進行相關源碼解析。探討它如何在非同步操作之間實現數據的流轉,以及它是如何在底層工作的。
使用方式
上面我們提到了AsyncLocal
可以在非同步操作間傳遞數據,我們在之前的文章<研究c#非同步操作async await狀態機的總結>一文中提到過非同步操作會涉及到線程切換的問題,接下來通過Task來模擬一個簡單非同步示例,來看一下它的工作方式是什麼樣的,以便加深對它的理解,先看一下示例
AsyncLocal<Person> context = new AsyncLocal<Person>();
context.Value = new Person { Id = 1, Name = "張三" };
Console.WriteLine($"Main之前:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
Console.WriteLine($"Task1之前:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
context.Value.Name = "李四";
Console.WriteLine($"Task1之後:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
await Task.Run(() =>
{
Console.WriteLine($"Task2之前:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
context.Value.Name = "王五";
Console.WriteLine($"Task2之後:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
Console.WriteLine($"Main之後:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
在上面的示例中,我們創建了一個AsyncLocal
實例,並賦值了一個Person
對象,然後我們創建了兩個Task
,分別執行了兩個非同步操作,並分別修改了AsyncLocal
中的Person
對象的值,分別在執行非同步之前執行非同步過程中和執行非同步之後列印值來觀察變化,執行程式輸出結果如下
Main之前:張三,ThreadId=1
Task1之前:張三,ThreadId=4
Task1之後:李四,ThreadId=4
Task2之前:李四,ThreadId=6
Task2之後:王五,ThreadId=6
Main之後:王五,ThreadId=6
從輸出結果來看,雖然我們在非同步中修改了AsyncLocal
里Person
對象的值,並且也發生了線程切換。但是它可以在非同步操作之間的數據共用和傳遞,使得我們在非同步間進行的數據就和在一個線程里操作數據一樣,讓我們可以忽略掉其實已經發生了多次線程切換。
探究本質
通過上面的示例,我們發現AsyncLocal
確實可以實現非同步之間的數據共用和傳遞,那麼它是如何實現的呢?接下來,我們通過先查看AsyncLocal
涉及到的相關源碼來探究一下。想弄明白它的流轉問題,需要研究兩個大方向,一個是AsyncLocal
的本身實現,一個是AsyncLocal
的流轉涉及到的非同步或者多線程相關這裡涉及到的主要是Task
和線程池
里的相關實現。由於非同步相關涉及到了一整個體系,所以但看某一點的時候可能不太容易理解,我們先從AsyncLocal
本身入手,然後從Task
入手,最後從線程池
入手,逐步探究AsyncLocal
如何進行數據流轉的。但是仍然希望能在閱讀本文之前先瞭解一下設計到該話題的相關文章,先對整體有一個整體的把握
- AsyncLocal細節的文章可以看一下黑洞大佬的<淺析 .NET 中 AsyncLocal 的實現原理>
- 非同步狀態機整體介紹可以看一下我之前的文章<研究c#非同步操作async await狀態機的總結>
AsyncLocal
雖然強烈建議先看一下上面推薦的文章,但是在這裡我們還是簡單介紹一下AsyncLocal
的實現,所以這裡我們簡單介紹一下,方便大家能直觀的看到。其實涉及到的比較簡單,就是看一下AsyncLocal
里涉及到關於Value的操作即可[點擊查看AsyncLocal.Value源碼