10

我想在TLS中存儲日誌上下文信息,以便我可以在入口點設置一個值,並在所有生成的堆棧中使用該值。這很好,但我也使用TPL和ThreadPool。問題就變成了如何將TLS數據遷移到其他線程。我可以自己做,但是我失去了像Parallel.For這樣好的方法。如何在使用TPL時管理線程本地存儲(TLS)?

使用TPL時有什麼方法可以複製TLS嗎?當它獲得await特性時,這也適用於C#。

謝謝, 埃裏克

回答

5

通常,這是通過使用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; 
    }); 
+0

謝謝里德 - 這是我想要的,但我找到了解決問題的另一種方法。儘管如此,這是我將很快使用的優秀內容。 –

+0

我想知道他們爲什麼包含這樣一個醜陋的超載?按照這個速度,只要初始化線程本地數據並在您的主代表中將其初始化即可。除非他們已經過perf優化..? –

+0

@ TimLovell-Smith線程本地數據在多個委託調用之間重複使用,因此無法在單個委託中進行初始化/最終化。 (這是關鍵;)) –

0

有,當然,另一種選擇:寫TaskLocal(T)類,像我們一樣,就是立足於當前任務的存儲,而不是當前線程。老實說,我不知道爲什麼微軟不把它作爲他們最初的任務實施的一部分。

重要實現注意事項:由於調用的await任務的代碼可以分割,並恢復爲不同任務id,你還需要做什麼,我們也做到了,實現映射新TaskID的TaskLocal(T)的方法到之前的任務,然後在任務開始時保存原始的TaskId,並在每次等待呼叫後映射它。

+0

演示這個的代碼示例會從我那裏得到一個+1 :-) – JoshBerke

+0

我會看看我能做些什麼...(: – Thought

+0

那會很棒! – JoshBerke