Task的运行原理和工作窃取(work stealing)

简介:

在net4.0以前,当调用ThreadPool.QueueUserWorkItem方法往线程池中插入作业时,会把作业内容(其实就是一个委托)放到线程池中的一个全局队列中,然后线程池中的线程按照先进先出的方式取出作业,并处理。

如下图中的方式,主程序创建了Item到Queue中,然后分配到了各个工作线程中。

poolinaction    
但是在.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被放入本地队列

llocalqueues

为什么要设计本地队列?这样做的优势是充分利用并行。随着越来越多线程竞争工作项,所有的线程访问单一的队列并不是最优的,并且也不安全。所以,将任务放入本地队列,并且由同一个线程处理,这就避免了竞争。   
本地队列中的Task,线程会按照LIFO的方式去处理。这是因为在大多数场景下,最后创建的Task可能仍然在cache中,处理它能够提供缓存命中率。显然这意味放弃部分公平性而保证性能。如下面的演示图,

工作者线程1创建了Task2,Task2创建了Task3,Task4,Task5,但最先处理的还是Task5。


线程窃取work stealing     
当A线程开始执行的时候,优先总是处理本地队列中的任务,当它发现本地队列已经空了,那么它会去全局队列中获取Task,当全局队列中也是空的,那么就会发生工作窃取(work stealing)。任务调度器会把该线程池中额外的任务分配给A线程处理,其效果就好比该线程会才从其他线程的队列中“窃取”一个Task来执行。这样的目的是提高了cpu的使用效率。

readpoollifo

这种策略是任务调度器的默认策略,通常是不需要改变的。如果需要改变,需要在创建任务时,设置任务的TaskCreationOptions.PreferFairness。

----------------------

参考资料

http://www.danielmoth.com/Blog/New-And-Improved-CLR-4-Thread-Pool-Engine.aspx
















本文转自cnn23711151CTO博客,原文链接: http://blog.51cto.com/cnn237111/1438624,如需转载请自行联系原作者









相关文章
|
7月前
|
Linux Go SoC
关于S3学习所涉及到的知识(二):Linux设备驱动suspend/resume的顺序
关于S3学习所涉及到的知识(二):Linux设备驱动suspend/resume的顺序
281 0
|
4月前
|
Cloud Native Java 调度
项目环境测试问题之线程同步器会造成执行完任务的worker等待的情况如何解决
项目环境测试问题之线程同步器会造成执行完任务的worker等待的情况如何解决
Session的工作机制
Session的工作机制
84 0
CacheCloud中Task任务执行过程
CacheCloud中Task任务执行过程实质是先将task进行堆积到taskQueue中,然后进行统一多线程进行处理。
122 0
|
存储 分布式计算 大数据
Spark 原理_运行过程_stage 和 task 的关系 | 学习笔记
快速学习 Spark 原理_运行过程_stage 和 task 的关系
211 0
Spark 原理_运行过程_stage 和 task 的关系 | 学习笔记
|
并行计算 算法 Java
JavaWeb - 工作窃取算法 Work-Stealing
JavaWeb - 工作窃取算法 Work-Stealing
408 0
JavaWeb - 工作窃取算法 Work-Stealing
|
应用服务中间件
Web应用程序[ROOT]似乎启动了一个名为[SeedGenerator Thread]的线程,但未能停止它。这很可能会造成内存泄漏。
Web应用程序[ROOT]似乎启动了一个名为[SeedGenerator Thread]的线程,但未能停止它。这很可能会造成内存泄漏。
1491 0
Web应用程序[ROOT]似乎启动了一个名为[SeedGenerator Thread]的线程,但未能停止它。这很可能会造成内存泄漏。
|
负载均衡 算法 Java
bthread源码剖析(二): 工作窃取与TaskGroup的run_main_task()
上一篇文章,介绍了TaskControl(简称TC)的初始化逻辑、worker的基本概念,并引出了TaskGroup(简称TG)的主要函数:run_main_task()。在谈run_main_task()之前,我们先看一下TG的几个主要成员。
404 0