启动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启动方式及源码探究的更多相关文章

  1. spring-boot-2.0.3之quartz集成,数据源问题,源码探究

    前言 开心一刻 着火了,他报警说:119吗,我家发生火灾了. 119问:在哪里? 他说:在我家. 119问:具体点. 他说:在我家的厨房里. 119问:我说你现在的位置. 他说:我趴在桌子底下. 11 ...

  2. 浅谈.Net Core DependencyInjection源码探究

    前言     相信使用过Asp.Net Core开发框架的人对自带的DI框架已经相当熟悉了,很多刚开始接触.Net Core的时候觉得不适应,主要就是因为Core默认集成它的原因.它是Asp.Net ...

  3. [Spark内核] 第34课:Stage划分和Task最佳位置算法源码彻底解密

    本課主題 Job Stage 划分算法解密 Task 最佳位置算法實現解密 引言 作业调度的划分算法以及 Task 的最佳位置的算法,因为 Stage 的划分是DAGScheduler 工作的核心,这 ...

  4. spring-cloud-sleuth+zipkin源码探究

    1. spring-cloud-sleuth+zipkin源码探究 1.1. 前言   粗略看了下spring cloud sleuth core源码,发现内容真的有点多,它支持了很多类型的链路追踪, ...

  5. Vue源码探究-全局API

    Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...

  6. Vue源码探究-事件系统

    Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...

  7. Vue源码探究-状态初始化

    Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...

  8. Vue源码探究-源码文件组织

    Vue源码探究-源码文件组织 源码探究基于最新开发分支,当前发布版本为v2.5.17-beta.0 Vue 2.0版本的大整改不仅在于使用功能上的优化和调整,整个代码库也发生了天翻地覆的重组.可见随着 ...

  9. Flink的Job启动TaskManager端(源码分析)

    前面说到了  Flink的JobManager启动(源码分析)  启动了TaskManager 然后  Flink的Job启动JobManager端(源码分析)  说到JobManager会将转化得到 ...

随机推荐

  1. Java方法调用数组,是否改变原数组元素的总结

    Java方法调用数组,是否改变原数组元素的总结 //个人理解, 欢迎吐槽 注意String是引用型变量, 我的理解也就是指向型, 指向一个数据或变量, 画图理解最容易, string 指向的 数据的值 ...

  2. Python学习-第三节part1: 关于函数

    一 为何要用函数之不用函数的问题 #1.代码的组织结构不清晰,可读性差 #2.遇到重复的功能只能重复编写实现代码,代码冗余 #3.功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护 ...

  3. PTA数据结构与算法题目集(中文) 7-6

    PTA数据结构与算法题目集(中文)  7-6 7-6 列出连通集 (25 分)   给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集.假设顶点从0到N−1编号.进行搜索时, ...

  4. Scratch 怎么打开SB文件怎么打开

    扩展名是.sb( )的文件均可以用匹配版本的scratch或比匹配版本高的scratch打开,列表如下:类型 可打开.sb ···1.4(1.3).sb2 ···2.0.sb3··· 3.0或3.0b ...

  5. 批处理 bat 查询局域网内在线电脑IP

    查看自己局域网的IP和物理网卡地址可以在 WIN+R –> 打开cmd 键入 arp -a 可以看到局域网中所有的在线IP COLOR 0A CLS @ECHO Off Title 查询局域网内 ...

  6. 30 HashSet

    /* * 使用HashSet存储字符串并遍历 * * Set的特点: * 无序(存储和读取的顺序可能不一样) * 不允许重复 * 没有整数索引 于List正好相反 */ public class Ha ...

  7. Python设计模式(8)-抽象工厂

    # coding=utf-8 这种方式反倒把事情做复杂了 可取之处在于有了更高层次的抽象 class IEmployee: def insert_employee(self): pass class ...

  8. app扫描二维码登陆

    先说明一下实现原理: 如同微信扫描登陆一样,就是一种pc的自动登陆授权.在网站首页得有切换登陆的选项:密码登陆 扫码登陆 当用户切换到扫码登陆时,向服务器请求一次获得一个唯一的uukey 利用这个uu ...

  9. std::string::copy函数

    size_t copy (char* s, size_t len, size_t pos = 0) const;

  10. 智能指针 unique_ptr

    unique_ptr 不共享它的指针.它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法. 1.不能进行复制构造和赋值操作(unique ...