Task的运行原理和工作窃取
在net4.0以前,当调用ThreadPool.QueueUserWorkItem方法往线程池中插入作业时,会把作业内容(其实就是一个委托)放到线程池中的一个全局队列中,然后线程池中的线程按照先进先出的方式取出作业,并处理。
如下图中的方式,主程序创建了Item到Queue中,然后分配到了各个工作线程中。
但是在.net 4.0以后,线程池做了一些改进,比如增加了TPL(Task Parallel Library),TPL使用到了.net 4.0中新增加的一些特性。这些特性只能通过TPL运用,不能直接通过ThreadPool类运用 。TPL中的Task并不是线程,Task的执行是需要依靠线程池中的线程来完成的。
创建和启动一个Task类似调用ThreadPool.QueueUserWorkItem,但不同的是线程池中的每一个线程都有一个本地队列。线程池通过一个任务调度器来分配任务,当主程序创建了一个Task后,由于创建这个Task的线程不是线程池中的线程,则任务调度器会把该Task放入全局队列中。
如果这个Task是由线程池中的线程创建,并且未设置TaskCreationOptions.PreferFairness标记(默认情况下未设置),则任务调度器会把该Task放入到该线程的本地队列中。如果设置了TaskCreationOptions.PreferFairness标记,则放入全局队列。
如下面的演示图,Task1和Task2都是主程序创建的,因此都是放在全局队列中,当工作者线程处理Task2时,创建了一个Task3,此时Task3被放入本地队列

为什么要设计本地队列?这样做的优势是充分利用并行。随着越来越多线程竞争工作项,所有的线程访问单一的队列并不是最优的,并且也不安全。所以,将任务放入本地队列,并且由同一个线程处理,这就避免了竞争。
本地队列中的Task,线程会按照LIFO的方式去处理。这是因为在大多数场景下,最后创建的Task可能仍然在cache中,处理它能够提供缓存命中率。显然这意味放弃部分公平性而保证性能。如下面的演示图,
工作者线程1创建了Task2,Task2创建了Task3,Task4,Task5,但最先处理的还是Task5。
线程窃取work stealing
当A线程开始执行的时候,优先总是处理本地队列中的任务,当它发现本地队列已经空了,那么它会去全局队列中获取Task,当全局队列中也是空的,那么就会发生工作窃取(work stealing)。任务调度器会把该线程池中额外的任务分配给A线程处理,其效果就好比该线程会才从其他线程的队列中“窃取”一个Task来执行。这样的目的是提高了cpu的使用效率。

这种策略是任务调度器的默认策略,通常是不需要改变的。如果需要改变,需要在创建任务时,设置任务的TaskCreationOptions.PreferFairness。
----------------------
参考资料
http://www.danielmoth.com/Blog/New-And-Improved-CLR-4-Thread-Pool-Engine.aspx
https://yq.aliyun.com/articles/429162
http://blog.51cto.com/cnn237111/1438624
http://www.cnblogs.com/lhstrong/articles/2095309.html
Task的运行原理和工作窃取的更多相关文章
- Task的运行原理和工作窃取(work stealing)
在net4.0以前,当调用ThreadPool.QueueUserWorkItem方法往线程池中插入作业时,会把作业内容(其实就是一个委托)放到线程池中的一个全局队列中,然后线程池中的线程按照先进先出 ...
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...
- 【转载】Spark系列之运行原理和架构
参考 http://www.cnblogs.com/shishanyuan/p/4721326.html 1. Spark运行架构 1.1 术语定义 lApplication:Spark Applic ...
- ASP.NET Core 运行原理解剖[1]:Hosting
ASP.NET Core 是新一代的 ASP.NET,第一次出现时代号为 ASP.NET vNext,后来命名为ASP.NET 5,随着它的完善与成熟,最终命名为 ASP.NET Core,表明它不是 ...
- [Spark内核] 第40课:CacheManager彻底解密:CacheManager运行原理流程图和源码详解
本课主题 CacheManager 运行原理图 CacheManager 源码解析 CacheManager 运行原理图 [下图是CacheManager的运行原理图] 首先 RDD 是通过 iter ...
- Spark核心技术原理透视一(Spark运行原理)
在大数据领域,只有深挖数据科学领域,走在学术前沿,才能在底层算法和模型方面走在前面,从而占据领先地位. Spark的这种学术基因,使得它从一开始就在大数据领域建立了一定优势.无论是性能,还是方案的统一 ...
- SPARK:作业基本运行原理
Spark作业基本运行原理: 我们使用spark-submit提交一个spark作业之后,这个作业就会启动一个对应的Driver进程.根据你使用的部署模式(deploy-mode)不同:1)Drive ...
- spark 任务运行原理
调优概述 在开发完Spark作业之后,就该为作业配置合适的资源了.Spark的资源参数,基本都可以在spark-submit命令中作为参数设置.很多Spark初学者,通常不知道该设置哪些必要的参数,以 ...
- java多线程 -- ForkJoinPool 分支/ 合并框架 工作窃取
Fork/Join 框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总. Fork/Join 框架与线程池的 ...
随机推荐
- element-ui 点击行如何获取table的行索引
文档中有一个tableRowClassName方法,可以获取到当前行的index, tableRowClassName ({row, rowIndex}) { //把每一行的索引放进row row.i ...
- python之shutil模块详解
shutil模块 -- --High-level file operations 高级的文件操作模块. os模块提供了对目录或者文件的新建/删除/查看文件属性,还提供了对文件以及目录的路径操作.比如 ...
- JavaScript验证时间格式
1. 短时间,形如 (13:04:06) function isTime(str) { var a = str.match(/^(\d{1,2})(:)?(\d{1,2})\2(\d{1,2})$/) ...
- Python学习过程笔记整理(四)
变量作用域 -分类 -全局(global):在函数外部定义:整个全局范围都有效 -局部(local):在函数内部定义:仅在局部范围有效 -提升局部变量为全局变量 -使用global -globals, ...
- Installshield相关的后续操作<一>图解
1.XML文件读取 选择需要读取XML文件 2.SQL数据库的安装 这里选择的文件是数据库脚本.如果脚本没有创建数据库的语句,还需手动输入. 3.自定义界面Dialogs 下一步: 上面红色框框里面是 ...
- jmeter线程组介绍
Jmeter中的测试计划是一直有的,但可以在右侧修改名字,要开始做具体测试设计前,都需要在测试计划下边添加一个线程组,添加路径为鼠标捕获测试计划后,点击鼠标右键->添加->Threads( ...
- Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第4节: recycler中获取对象
Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第四节: recycler中获取对象 这一小节剖析如何从对象回收站中获取对象: 我们回顾上一小节demo的ma ...
- To Do List | 事实上是咕咕咕计划
1.写一两篇关于数学的博文 类似于这种反演啥的或者说是FFT一些更本质的东西趴...反正是我根本不会的东西 再写一点自己会的东西趴...(好像也只有什么课本上的东西讲讲了,不过应该会写一些自己曾经发现 ...
- nodejs的Cannot find module 'body-parser'
http://blog.csdn.net/u014345860/article/details/77769253
- Scrum Meeting 12 -2014.11.18
今天的任务都比较顺利,测试暂时还没发现特别的问题. Member Today’s task Next task 林豪森 与其他小组商讨整合问题 与其他小组商讨整合问题 宋天舒 测试项目功能实现 测试项 ...