你的位置:首页 > 软件开发 > ASP.net > .NET Task揭秘(一)

.NET Task揭秘(一)

发布时间:2016-12-20 19:00:21
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.DefaultTaskCreationOptions.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 (#换成@)。