我想在TLS中存儲日誌上下文信息,以便我可以在入口點設置一個值,並在所有生成的堆棧中使用該值。這很好,但我也使用TPL和ThreadPool。問題就變成了如何將TLS數據遷移到其他線程。我可以自己做,但是我失去了像Parallel.For這樣好的方法。如何在使用TPL時管理線程本地存儲(TLS)?
使用TPL時有什麼方法可以複製TLS嗎?當它獲得await特性時,這也適用於C#。
謝謝, 埃裏克
我想在TLS中存儲日誌上下文信息,以便我可以在入口點設置一個值,並在所有生成的堆棧中使用該值。這很好,但我也使用TPL和ThreadPool。問題就變成了如何將TLS數據遷移到其他線程。我可以自己做,但是我失去了像Parallel.For這樣好的方法。如何在使用TPL時管理線程本地存儲(TLS)?
使用TPL時有什麼方法可以複製TLS嗎?當它獲得await特性時,這也適用於C#。
謝謝, 埃裏克
通常,這是通過使用Parallel.For超負荷已經提供了用於線程本地數據處理。
這個重載允許你提供一個初始化和一個終結委託,它有效地成爲你的線程本地數據的每個線程的初始化,最後還有一個簡化函數將結果「合併」在一起(每運行一次線)。 I wrote about this in detail here。
的基本形式是做這樣的事情:
object sync = new object();
double result = 0;
Parallel.For(0, collection.Count,
// Initialize thread local data:
() => new MyThreadSpecificData(),
// Process each item
(i, pls, currentThreadLocalData) =>
{
// Generate a NEW version of your local state data
MyThreadSpecificData newResults = ProcessItem(collection, i, currentThreadLocalData);
return newResults;
},
// Aggregate results
threadLocalData =>
{
// This requires synchronization, as it happens once per thread,
// but potentially simultaneously
lock(sync)
result += threadLocalData.Results;
});
我找到了另一種解決方案,它不需要代碼的問題。我能夠使用CallContext將數據附加到「邏輯線程」。這些數據從起始線程傳輸到由TPL和ThreadPool生成的線程。
只是FYI - 這個機制比使用TLS慢得多,因爲它通過每個上下文調用序列化數據... –
謝謝里德 - 這是我想要的,但我找到了解決問題的另一種方法。儘管如此,這是我將很快使用的優秀內容。 –
我想知道他們爲什麼包含這樣一個醜陋的超載?按照這個速度,只要初始化線程本地數據並在您的主代表中將其初始化即可。除非他們已經過perf優化..? –
@ TimLovell-Smith線程本地數據在多個委託調用之間重複使用,因此無法在單個委託中進行初始化/最終化。 (這是關鍵;)) –