在没有 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执行的内联性线程重入相关推荐

  1. c语言中关于宏和内联说法正确的是, 2011年1月高等教育自学考试全国统一命题考试 C++程序设计试题...

    版权声明:以上文章中所选用的图片及文字来源于网络以及用户投稿,由于未联系到知识产权人或未发现有关知识产权的登记,如有知识产权人并不愿意我们使用,如果有侵权请立即联系:55525090@qq.com,我 ...

  2. c++中内敛函数_C++ 内联函数 | 菜鸟教程

    内联函数: Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数. 定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用. 优点: 当函数体比较 ...

  3. CSS中的块元素,内联元素,内联块元素

    块元素,内联元素,内联块元素 元素就是标签,布局中常用的有三种标签,块元素.内联元素.内联块元素,了解这三种元素的特性,才能熟练的进行页面布局. 块元素 块元素,也可以称为行元素,布局中常用的标签如: ...

  4. mysql全联合查询,MySQL中的联合查询(内联、左联、外联、右联、全联)

    联合查询效率较高,举例子来说明联合查询:内联inner join .左联left outer join .右联right outer join .全联full outer join 的好处及用法. T ...

  5. 玩转CSS中块元素、内联元素、内联块元素

    元素就是标签,布局中常用的有三种标签,块元素.内联元素.内联块元素,了解这三种元素的特性,才能熟练的进行页面布局. 1.块元素  块元素,也可以称为行元素,布局中常用的标签如:div.p.ul.li. ...

  6. 在Vue中使用样式——使用内联样式

    使用内联样式

  7. go 基准测试 找不到函数_Go 中的内联优化 | Linux 中国

    本文讨论 Go 编译器是如何实现内联的,以及这种优化方法如何影响你的 Go 代码.https://linux.cn/article-12176-1.html作者:Dave Cheney译者:Xiaob ...

  8. 在Visual C++ 中使用内联汇编

    一. 优点 使用内联汇编可以在 C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤.在 Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如 MASM 一类的独立汇编工 ...

  9. 在 VC++ 中使用 内联汇编

    From:https://blog.csdn.net/root19881111/article/details/8450266 VC++内联汇编(MSDN相关内容完整翻译):http://www.cp ...

最新文章

  1. 使用C#中的ref关键字,用2个简单例子来说明
  2. C++入门教程,全套C++基础教程(已更新完毕)
  3. 3、MySQL执行事务的语法和流程
  4. clustered index disadvantages in mysql
  5. boost::detail::sp_convertible相关的测试程序
  6. Windows上PHP扩展的实现,部署及应用
  7. 用C++解析HTTP下载下来的HTML文档
  8. 产生数(信息学奥赛一本通-T1361)
  9. 川大计算机专业导师冯子亮,问问川大计算机研究生招收的小专业有哪些
  10. RSA加解密用途简介及java示例
  11. 如何开发一款高大上的android应用的必备知识
  12. java jpa 教程 查询_Spring Boot JPA 使用教程
  13. JAVA常用框架及漏洞
  14. 【机器学习】TensorFlow共享GPU资源
  15. 报错 Duplicate keys detected
  16. 第十篇:SpringBoot集成支付宝接口扫码支付
  17. Element.closest() 兼容IE
  18. redhat7.6配置网络yum源
  19. 谭咏麟-讲不出再见-国语谐音歌词
  20. 6.openCV调整图像大小新思路(cv2.resize和imutils.resize)

热门文章

  1. IAR EW6.30版本下建立STM32工程(芯片型号STM32F105VC)
  2. bool 变量想为什么一般初始化为FALSE 比较好?
  3. <java并发编程实践>读书笔记二
  4. Spring cloud技术栈
  5. springmvc十二:@PathVariable
  6. 数据结构:栈--计算表达式
  7. python四十五:归一化继承
  8. 微信XML,Object,MAP相互转换
  9. Android 获取应用程序版本号
  10. [Linux] Linux smaps接口文件结构