這幾天太忙沒時間寫博客,今天回家就簡單的看了下ThreadPool的源碼,發(fā)現(xiàn)有一個好玩的東西,叫做”執(zhí)行上下文“,拽名叫做:”ExecutionContext“。
一:ThreadPool的大概流程。
第一步:它會調(diào)用底層一個helper方法。

第二步:走進(jìn)這個helper方法,我們會發(fā)現(xiàn)有一個隊列,并且這個隊列的item必須是QueueUserWorkItemCallback的實(shí)例,然后這就激發(fā)了我的
興趣,看看QueueUserWorkItemCallback到底都有些什么?

第三步:走到QueueUserWorkItemCallback實(shí)例的時候,會依次把callback,state參數(shù)給當(dāng)前類的字段,并且有一個好玩的地方的就是根據(jù)
ExecutionContext.IsFlowSupPRessed()來判斷要不要把”當(dāng)前線程的上下文“給”調(diào)用線程“?這個放在后面講,然后我們看到了一
個 IThreadPoolWorkItem.ExecuteWorkItem()方法,里面有ContextCallback委托的調(diào)用,也許這個就是隊列中每一項中要調(diào)用
的方法。

第四步:然后我們再回到第二步中的 ThreadPoolGlobals.workQueue.Enqueue(callback, true)方法進(jìn)去看看,并且我們的callback,state都被封裝成了
QueueUserWorkItemCallback放到隊列中了,從這個Enqueue方法中,我們看到了一個this.EnsureThreadRequested(),走到方法里面去了
之后,這時候急迫想去看ThreadPool.RequestWorkerThread()方法,但它是個extern方法,不過從名字上看就是請求工作線程去執(zhí)行,所以并
沒有真實(shí)的發(fā)現(xiàn)到所謂的線程池這個東西。(由于不能窺全貌,可能有些說的不太對)

好了,上面的剖析大概就這樣了,其實(shí)所有的方法都封裝成了底層的一個類放在一個隊列中,應(yīng)該是用上面的for來挑選空閑的工作線程去執(zhí)行我們
的任務(wù),里面還有很多代碼,比較復(fù)雜,一時也看不懂什么。
二:執(zhí)行上下文
剛才第三步說到了”執(zhí)行上下文“,看到這個方法里面有一個if條件,然后看到有一個 ExecutionContext.IsFlowSuppressed()方法,從名字上
就可以看出叫”阻止流動“,如果為否的話,就用Capture來抓當(dāng)前線程的”上下文信息“,然后我們就順藤摸瓜的往下看,從這個方法來看,我們依次
去抓取調(diào)用線程的”安全設(shè)置“,”宿主設(shè)置“,”同步信息“,“邏輯調(diào)用”,并且可以看到logicalCallContext有值的話,會做一個copy的操作。

其實(shí)這個logicalCallContext非常有意思,里面是一個KV結(jié)構(gòu),源碼里面也說了,只要我不IsFlowSuppressed,那么主線程的上下文會flow到
工作線程,那么logicalCallContext怎么設(shè)置呢?其實(shí)在C#里面的CallContext里面的LogicalSetData和LogicalGetData就可以做這些事情。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 CallContext.LogicalSetData("name", "ctrip"); 6 7 Thread.CurrentThread.IsBackground = true; 8 9 ThreadPool.QueueUserWorkItem((o) =>10 {11 var t = Thread.CurrentThread.ManagedThreadId;12 13 var result = CallContext.LogicalGetData("name");14 15 Console.WriteLine("我是工作線程: Name:" + result);16 17 });18 19 Console.Read();20 }21 }

可以看到我在主線程設(shè)置的值被工作線程讀到了,是不是很有意思,給我們線程間傳值提供了另一種方法,剛才我們也看到,一旦IsFlowSuppressed
了,那么context就返回null,也就阻止了將logicCallContext的信息傳遞給工作線程,可以用ExecutionContext.SuppressFlow()做到,下面具體
看一看。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 CallContext.LogicalSetData("name", "ctrip"); 6 7 //阻止logical數(shù)據(jù)流動 8 ExecutionContext.SuppressFlow(); 9 10 Thread.CurrentThread.IsBackground = true;11 12 ThreadPool.QueueUserWorkItem((o) =>13 {14 var t = Thread.CurrentThread.ManagedThreadId;15 16 var result = CallContext.LogicalGetData("name");17 18 Console.WriteLine("我是工作線程: Name:" + result);19 20 });21 22 Console.Read();23 }24 }

現(xiàn)在結(jié)論也出來了,去Capture主線程的上下文是需要很多的代碼量,所以如果工作線程用不到主線程的這些信息,那么你應(yīng)該做到顯示關(guān)閉,這樣
對工作線程的性能來說有很大的好處。
新聞熱點(diǎn)
疑難解答