Task启动方式及源码探究
启动Task有几种方式:
1.Task.Run()
2.new TaskFactory.StartNew()
3.var t=new Task(); t.start();
平时用的最多是第一和第二种,那么他们之间有什么差异?接下来通过两个demo进行说明。
static void Main(string[] args)
{
for (int i = ; i < ; i++)
{
Task.Run(() => Sayhi("task"));
new TaskFactory().StartNew(() => Sayhi("taskfactory"));
} Console.ReadLine();
} public static void Sayhi(string method)
{
Console.WriteLine(method+":"+Thread.CurrentThread.ManagedThreadId);
}
运行结果:
task:5
taskfactory:4
taskfactory:6
task:7
task:5
task:6
taskfactory:7
taskfactory:5
task:4
taskfactory:6
通过以上结果可以猜测task跟taskfactory运行的模式基本一致,线程重复使用,猜测是通过线程池来调度。
接下来,我给TaskFactory().StartNew添加一个参数TaskCreationOptions.LongRunning
new TaskFactory().StartNew(() => Sayhi("taskfactory"),TaskCreationOptions.LongRunning);
运行结果:
task:9
task:9
task:4
taskfactory:5
task:6
task:7
taskfactory:8
taskfactory:10
taskfactory:11
taskfactory:12
如果你眼神犀利,相信已经看出其中的差异。没错,taskfactory每次运行都是一个新的线程,由此可以猜测TaskCreationOptions.LongRunning这个参数会决定task运行的命运,它将不会进入线程池,自己单飞了。
综上所述,有以下猜测:
1.Task.Run()与TaskFactory().StartNew()运行模式一致
2.都是线程池调度
3.TaskCreationOptions=TaskCreationOptions.LongRunning时,不由线程池调度。
为了验证猜测,让我们来翻一下源码。
Task.Run()
public static Task Run(Action action)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark); }
new TaskFactory().StartNew()
public Task StartNew(Action action)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask),
m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark);
}
可以看到,无论是Task.Run()还是new TaskFactory().StartNew()都是调用了Task.InternalStartNew方法,而Task.Run是默认的参数,TaskFactory().StartNew()拥有更多的自由度。由此验证猜测1。
继续跳进,最终调用ScheduleAndStart方法
internal void ScheduleAndStart(bool needsProtection)
{
try
{
// Queue to the indicated scheduler.
m_taskScheduler.InternalQueueTask(this); //调度任务
}
catch (ThreadAbortException tae)
{
AddException(tae);
FinishThreadAbortedTask(true, false);
}
}
m_taskScheduler实例就是上面的TaskScheduler.Default,来瞧瞧是装了什么东西
private static readonly TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler(); public static TaskScheduler Default
{
get
{
return s_defaultTaskScheduler;
}
}
ThreadPoolTaskScheduler,瞧瞧这单词是不是有内味了,来,答案快水落石出了。
protected internal override void QueueTask(Task task)
{
if ((task.Options & TaskCreationOptions.LongRunning) != )
{
// Run LongRunning tasks on their own dedicated thread.
Thread thread = new Thread(s_longRunningThreadWork);
thread.IsBackground = true; // Keep this thread from blocking process shutdown
thread.Start(task);
}
else
{
// Normal handling for non-LongRunning tasks.
bool forceToGlobalQueue = ((task.Options & TaskCreationOptions.PreferFairness) != );
ThreadPool.UnsafeQueueCustomWorkItem(task, forceToGlobalQueue);
}
}
看到这里相信不需要我再说什么了... 猜测验证成功。
总结以下:
1.Task.Run()是TaskFactory().StartNew()的其中一种形式。TaskFactory().StartNew()拥有更多自由度。
2.Task.Run()是线程池调度,TaskFactory().StartNew()参数TaskCreationOptions=TaskCreationOptions.LongRunning时,不由线程池调度。
源码链接:https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs
Task启动方式及源码探究的更多相关文章
- spring-boot-2.0.3之quartz集成,数据源问题,源码探究
前言 开心一刻 着火了,他报警说:119吗,我家发生火灾了. 119问:在哪里? 他说:在我家. 119问:具体点. 他说:在我家的厨房里. 119问:我说你现在的位置. 他说:我趴在桌子底下. 11 ...
- 浅谈.Net Core DependencyInjection源码探究
前言 相信使用过Asp.Net Core开发框架的人对自带的DI框架已经相当熟悉了,很多刚开始接触.Net Core的时候觉得不适应,主要就是因为Core默认集成它的原因.它是Asp.Net ...
- [Spark内核] 第34课:Stage划分和Task最佳位置算法源码彻底解密
本課主題 Job Stage 划分算法解密 Task 最佳位置算法實現解密 引言 作业调度的划分算法以及 Task 的最佳位置的算法,因为 Stage 的划分是DAGScheduler 工作的核心,这 ...
- spring-cloud-sleuth+zipkin源码探究
1. spring-cloud-sleuth+zipkin源码探究 1.1. 前言 粗略看了下spring cloud sleuth core源码,发现内容真的有点多,它支持了很多类型的链路追踪, ...
- Vue源码探究-全局API
Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...
- Vue源码探究-事件系统
Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...
- Vue源码探究-状态初始化
Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...
- Vue源码探究-源码文件组织
Vue源码探究-源码文件组织 源码探究基于最新开发分支,当前发布版本为v2.5.17-beta.0 Vue 2.0版本的大整改不仅在于使用功能上的优化和调整,整个代码库也发生了天翻地覆的重组.可见随着 ...
- Flink的Job启动TaskManager端(源码分析)
前面说到了 Flink的JobManager启动(源码分析) 启动了TaskManager 然后 Flink的Job启动JobManager端(源码分析) 说到JobManager会将转化得到 ...
随机推荐
- ios 13 陀螺仪DeviceOrientationEvent需要申请用户权限
有些代码跑着跑着就报错了,有些陀螺仪用着用着就不能用了. 目前时间是2020.4.4,发现 ios 13系统调用陀螺仪 需要申请用户权限(这应该是个趋势,后面安卓应该陆续跟进).具体实现来看下: 1 ...
- js 的位运算
api 用途 待更...
- RPC框架实现(一) Protobuf的rpc实现
概述 RPC框架是云端服务基础框架之一,负责云端服务模块之间的项目调用,类似于本地的函数调用一样方便.常见的RPC框架配带的功能有: 编解码协议.比如protobuf.thrift等等. 服务发现.指 ...
- Aggressive cows(二分法)
Aggressive cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 28666 Accepted: 13146 Des ...
- 从养孩子谈谈 IO 模型(一)
同步/异步.阻塞/非阻塞 说的是一回事儿吗? 同步/异步.阻塞/非阻塞 你能通俗易懂的讲清楚吗? Java 中的 BIO.NIO.AIO 你了解吗? Socket 编程你还会吗? Linux 操作系统 ...
- eclipse常用功能及快捷键
1.更改默认字体 Window->Preferences->General->Appearance->Colorsand Fonts ->Basics->Text ...
- man手册、zip备份
...
- flask-sqlalchemy的基本使用
flask-sqlalchemy 1 .配置应用和基本使用 和sqlalchemy一样,先定义好数据库配置和db_url.然后在app的config加入SQLALCHEMY_DATABASE_URI等 ...
- mongodb 指令
db.xxx.stats() 查看表的大小 db.xxx.remove({'endtime':{'$lte':ISODate('2018-10-01')}}) 删除小于等于固定时间的数据. db.us ...
- Java第十天,多态
多态 一.多态的定义: 一个对象拥有多种形态,这就是对象的多态性.也就是说多态针对的是对象.多态的前提是接口和继承(C++中实行多继承,不存在接口). 二.多态在代码中的形式: 父类 对象名 = ne ...