Task为.NET提供了基于任务的异步模式,它不是线程,它运行在线程池的线程上。本着开源的精神, 本文以解读基于.NET4.5 Task源码的方式来揭秘Task的实现原理。 Task的创建Task的创建方式主要有2种:Task.Run 和Task.Factory.StartN ...
Task为
.NET提供了基于任务的
异步模式,它不是
get='_blank'>线程,它运行在线程池的线程上。本着开源的精神, 本文以解读基于.NET4.5 Task源码的方式来揭秘Task的实现原理。调用了
Task.InternalStartNew,第一个参数为null,并传入
TaskScheduler.Default和
TaskCreationOptions.DenyChildAttach.也是调用
Task.InternalStartNew,第一个参数为
internalCurrent,当前为null,并传入
GetDefaultScheduler(internalCurrent)和
m_defaultCreationOptions。如果
internalCurrent不为空而且options是
TaskCreationOptions.HideScheduler,那么启用
internalCurrent的TaskScheduler。可惜
internalCurrent为null,所以启用默认的TaskScheduler,跟入代码发现默认的TaskScheduler是
ThreadPoolTaskScheduler,看名字就知道用的是线程池的任务调度,跟“黑盒”传说的一样的。
m_defaultCreationOptions在Task.Factory的默认无参构造函数里被赋值
TaskCreationOptions.None。目前来看两个方法最大的区别在于
TaskCreationOption的不同,一个是
DenyChildAttach,另一个是
None。首先实例化一个Task:如果option是
AttachToParent,那么
internalCurrent就赋值给
m_parent,目前为null,
SelfReplicating是用来做并行计算的,会在TPL里详解。随后调用
TaskConstructorCore。如果options不为
DenyChildAttach而且
m_parent不为空,则把当前task作为child添加到
m_parent。也就是说
Task.Run不允许把要执行的task作为当前task的child。ExecutionContext包含了SecurityContext,SynchronizationContext以及LogicalCallContext,其中SynchronizationContext需要做CreateCopy,LogicalCallContext需要做clone,所有这一切都是用户态的,不涉及内核,性能棒棒哒!
FireTaskScheduledIfNeeded判断是否开启EWT Trace,接着调用
ThreadPoolTaskScheduler.QueueTask。如果options是
LongRunning,那么单独创建一个线程执行该任务(
ExecuteEntry),否则就调用
ThreadPool.UnsafeQueueCustomWorkItem,这个方法我们熟,还记得在.net线程池内幕里有讲到的global work queue和local work queue吗?给
ThreadPool添加一个任务实际上是在global work queue添加一个任务,而task就是往local work queue里添加任务。由于线程已经执行过任务(global的也有可能是local的),所以代码会走到
queueThreadLocals.workStealingQueue.LocalPush(callback)。Local work queue(m_array)首先被限死为32,如果queue超过最大数了,则扩大为原来的2倍,以此类推。这里也使用了自旋锁和内存写屏障来代替同步锁提高性能。
原标题:.NET Task揭秘(一)
关键词:.NET
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们:
admin#shaoqun.com
(#换成@)。