TPL中Task执行的内联性线程重入
在沒有 TPL(Task Parallel Library)之前,使用 ThreadPool 處理多線程事務及等待,可能類似如下代碼:
1 class Program 2 { 3 [ThreadStatic] 4 static int PerThreadValue; 5 6 static void Main(string[] args) 7 { 8 Console.WriteLine("Main thread: {0}", 9 Thread.CurrentThread.ManagedThreadId); 10 11 Console.WriteLine(); 12 13 for (int i = 1; i <= 5; i++) 14 { 15 AutoResetEvent signalOuter = new AutoResetEvent(false); 16 ThreadPool.QueueUserWorkItem((s) => 17 { 18 PerThreadValue = i; 19 Console.WriteLine("Launch thread: {0}, Value: {1}", 20 Thread.CurrentThread.ManagedThreadId, PerThreadValue); 21 22 AutoResetEvent signalInner = new AutoResetEvent(false); 23 ThreadPool.QueueUserWorkItem((n) => 24 { 25 Console.WriteLine(" Nested thread: {0}, Value: {1}", 26 Thread.CurrentThread.ManagedThreadId, PerThreadValue); 27 signalInner.Set(); 28 }); 29 signalInner.WaitOne(); 30 31 Console.WriteLine(" Launch back thread: {0}, Value: {1}", 32 Thread.CurrentThread.ManagedThreadId, PerThreadValue); 33 signalOuter.Set(); 34 }); 35 signalOuter.WaitOne(); 36 } 37 38 Console.ReadKey(); 39 } 40 }ThreadPool 會為每個應用程序域維護 FIFO 的先入先出隊列,每當調用 QueueUserWorkItem 時,線程池會將給定的任務放入隊列中,等到有下一個可用線程時,從隊列中取出執行。
所以執行的解決過發現每個任務都執行在不同的線程上。
當 .NET Framework 4 提供 TPL 庫之后,我們可以通過另一種寫法來完成同樣的任務。
1 class Program 2 { 3 [ThreadStatic] 4 static int PerThreadValue; 5 6 static void Main(string[] args) 7 { 8 Console.WriteLine("Main thread: {0}", 9 Thread.CurrentThread.ManagedThreadId); 10 11 Console.WriteLine(); 12 13 for (int i = 1; i <= 5; i++) 14 { 15 Task.Factory.StartNew( 16 () => 17 { 18 PerThreadValue = i; 19 Console.WriteLine("Launch thread: {0}, Value: {1}", 20 Thread.CurrentThread.ManagedThreadId, PerThreadValue); 21 22 Task.Factory.StartNew( 23 () => 24 { 25 Console.WriteLine(" Nested thread: {0}, Value: {1}", 26 Thread.CurrentThread.ManagedThreadId, PerThreadValue); 27 }).Wait(); 28 29 Console.WriteLine(" Launch back thread: {0}, Value: {1}", 30 Thread.CurrentThread.ManagedThreadId, PerThreadValue); 31 }).Wait(); 32 } 33 34 Console.ReadKey(); 35 } 36 }通常,我們會看到的結果,嵌套的 Task 與外部調用及等待的 Task 使用了相同的線程池線程。
如果機器夠快的話,基本上所有 Task 都在同一個線程上執行。
?
TPL 中使用 TaskScheduler 來調度 Task的 執行,而 TaskScheduler 有一個特性名為 “Task Inlining”。
當外部 ThreadPool 線程正在阻塞并等待嵌套的 NestedTas k完成時,NestedTask 有可能在該等待的線程上執行。
這樣做的優點是可以提高性能,因為節省并重用了被阻塞的線程。
在使用可能碰到的問題:
如果使用 ThreadStatic 標記某變量,則使該變量為每線程 TLS 獨立存儲,同時也意圖該變量始終在同一線程中共享。
但在所示例子中,如果在父 Task 及執行線程中指定了變量的值,而子 Task 及相同執行線程則使用了相同的變量值, 則在某種需求下會產生問題。
本文轉自匠心十年博客園博客,原文鏈接:http://www.cnblogs.com/gaochundong/archive/2013/04/19/tpl_task_inlining.html,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的TPL中Task执行的内联性线程重入的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL*Loader 笔记 (一) 热身
- 下一篇: HashMap原理总结