博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TPL中Task执行的内联性线程重入
阅读量:6364 次
发布时间:2019-06-23

本文共 2925 字,大约阅读时间需要 9 分钟。

在没有 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://xnama.baihongyu.com/

你可能感兴趣的文章
详解Java中staitc关键字
查看>>
《Unity着色器和屏幕特效开发秘笈》—— 第3章 利用镜面反射让游戏闪耀起来...
查看>>
前中情局局长:FBI目的是从根本上改善iPhone
查看>>
测试界和学术界应该架起桥梁
查看>>
大隐隐于市,你身边的那些安全隐患你都知道么?
查看>>
这个物联网处理器号称全世界体型最小
查看>>
Decorator模式及其他相似的模式
查看>>
物联网市场迅猛发展 “中国芯”如何把握机会?
查看>>
aws 上使用elb 的多域名问题
查看>>
从 MyEclipse 到 IntelliJ IDEA
查看>>
环球花木网的目标就是致力于打造成为“园林相关行业的专业性门户网站
查看>>
《编写高质量代码:改善c程序代码的125个建议》—— 建议14-1:尽量避免对未知的有符号数执行位操作...
查看>>
《C语言编程魔法书:基于C11标准》——2.2 整数在计算机中的表示
查看>>
全球程序员编程水平排行榜TOP50,中国排名第一
查看>>
HDFS 进化,Hadoop 即将拥抱对象存储?
查看>>
Edge 浏览器奇葩 bug:“123456”打印成“114447”
查看>>
Sirius —— 开源版的 Siri ,由 Google 支持
查看>>
《OpenGL ES应用开发实践指南:Android卷》—— 2.7 小结
查看>>
《Windows Server 2012活动目录管理实践》——第 2 章 部署第一台域控制器2.1 案例任务...
查看>>
Java Date Time 教程-时间测量
查看>>