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,如需转载请自行联系原作者

目录
相关文章
|
6月前
|
Java C#
C#学习相关系列之多线程(七)---Task的相关属性用法
C#学习相关系列之多线程(七)---Task的相关属性用法
|
6月前
|
Java C#
C#学习相关系列之多线程(六)----Task的初级使用
C#学习相关系列之多线程(六)----Task的初级使用
|
Dart 调度 Android开发
Flutter 95: 图解 Dart 单线程实现异步处理之 Task Queue
0 基础学习 Flutter,第九十五节:学习一下 MicroTask 和 EventTask 任务调度!
516 0
Flutter 95: 图解 Dart 单线程实现异步处理之 Task Queue
|
C#
WPF异常捕获三种处理 UI线程, 全局异常,Task异常
原文:WPF异常捕获三种处理 UI线程, 全局异常,Task异常 protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);RegisterEvents();} private void RegisterEvents(){//TaskScheduler.
2534 0
【多线程】Task
介绍   Task是.NET推出数据任务处理的工作类。位于System.Threading.Tasks命名空间下,通过命名空间也可以看出是个多线程类。 创建Task:   Task有很多构造函数,无参有参都有,想了解更多可以去官网查看。
804 0
|
Java 调度
多线程——Task
背景:                 以前想用Semaphore来处理并发访问资源的问题,后来把方案拿给前辈们看的时候,他们说这样也行,但是最好用Task处理,比较简单。所以,顺便学习了下Task.
960 0
|
C#
5天玩转C#并行和多线程编程 —— 第四天 Task进阶
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task 5天玩转C#并行和多线程编程 —— 第四天 Task进阶 5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结    一、Task的嵌套    Task中还可以再嵌套Task,Thread中能不能这样做,我只能说我是没这样写过。
1565 0
|
C# Java 调度
5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task 5天玩转C#并行和多线程编程 —— 第四天 Task进阶 5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结     对于多线程,我们经常使用的是Thread。
1319 0
|
并行计算 Java Windows
重新想象 Windows 8 Store Apps (43) - 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)
原文:重新想象 Windows 8 Store Apps (43) - 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel) [源码下载] 重新想象 Windows 8 Store Apps (43) - 多线程之任务: Task 基础, 多任务并行执行, 并行运算(P...
795 0
|
vr&ar Windows 编译器
重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
原文:重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 [源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IA...
964 0