平时我们在用多线程开发的时候少不了Task,确实task给我们带来了巨大的编程效率,在Task底层有一个TaskScheduler,它决定了task该如何被调度,而

在.net framework中有两种系统定义Scheduler,第一个是Task默认的ThreadPoolTaskScheduler,还是一种就是SynchronizationContextTaskScheduler,

以及这两种类型之外的如何自定义,这篇刚好和大家分享一下。

一: ThreadPoolTaskScheduler

这种scheduler机制是task的默认机制,而且从名字上也可以看到它是一种委托到ThreadPool的机制,刚好也从侧面说明task是基于ThreadPool基础上的

封装,如果想具体查看代码逻辑,你可以通过ILSpy反编译一下代码看看:

   protected internal override void QueueTask(Task task)
{
if ((task.Options & TaskCreationOptions.LongRunning) != TaskCreationOptions.None)
{
new Thread(ThreadPoolTaskScheduler.s_longRunningThreadWork)
{
IsBackground = true
}.Start(task);
return;
}
bool forceGlobal = (task.Options & TaskCreationOptions.PreferFairness) > TaskCreationOptions.None;
ThreadPool.UnsafeQueueCustomWorkItem(task, forceGlobal);
}

从上面的代码中可以看到如下逻辑,如果当前Task上的TaskCreationOptions设置为LongRunning的话,这个task就会委托到Thread中去执行,这样的

好处显而易见,如果长时间运行的task占用着ThreadPool的线程,这时候ThreadPool为了保证线程充足,会再次开辟一些Thread,如果耗时任务此时释放了,

会导致ThreadPool线程过多,上下文切换频繁,所以这种情况下让Task在Thread中执行还是非常不错的选择,当然如果你不指定这个LongRunning的话,那就

是在ThreadPool上执行,不信的话,还可以用windbg去验证一下。。。

     static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("hello world!!!");
}, TaskCreationOptions.LongRunning); Console.Read();
}

如果大家对windbg不熟悉的话,也没关系,先暂且不讨论,我们只要把TaskCreationOptions枚举去掉,然后用这种形式的!threads给大家展示下不同

应该就非常明朗了。

        static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("hello world!!!");
}); Console.Read();
}

好了,当你看到这两张图,你应该明白带LongRunning的话,thread中没有带(ThreadPool Worker)标记,也就表明当前是单独开辟的线程,而下面

这张图很明显带有这种标识,表示当前是委托在ThreadPool中执行的。

二:SynchronizationContextTaskScheduler

从这个名字中就可以看到,这是一个同步上下文的taskscheduler,原理就是把繁重的耗时工作丢给ThreadPool,然后将更新UI的操作丢给 UI线程的

队列中,由UIThread来执行,具体的也可以在这种scheduler中窥得一二。

        protected internal override void QueueTask(Task task)
{
this.m_synchronizationContext.Post(SynchronizationContextTaskScheduler.s_postCallback, task);
}

然后可以从s_postCallback上看到里面有一个Invoke函数,如下图:

  public virtual void Post(SendOrPostCallback d, object state)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);
}

有了这个基础我们再来看一下代码怎么写,可以看到,下面这段代码是不阻塞UIThread的,完美~~~

          private void button1_Click(object sender, EventArgs e)
{
Task task = Task.Factory.StartNew(() =>
{
//复杂操作,等待10s
Thread.Sleep(); }).ContinueWith((t) =>
{
button1.Text = "hello world";
}, TaskScheduler.FromCurrentSynchronizationContext());
}

三:自定义TaskScheduler 

  我们知道在现有的.net framework中只有这么两种TaskScheduler,有些同学可能想问,这些Scheduler我用起来不爽,我想自定义一下,这个可

以吗?当然!!!如果你想自定义,只要自定义一个类实现一下TaskScheduler就可以了,然后你可以将ThreadPoolTaskScheduler简化一下,即我要

求所有的Task都需要走Thread,杜绝使用TheadPool,这样可以吗,当然了,不信你看。

 namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("hello world!!!");
}, new CancellationToken(), TaskCreationOptions.None, new PerThreadTaskScheduler()); Console.Read();
}
} /// <summary>
/// 每个Task一个Thread
/// </summary>
public class PerThreadTaskScheduler : TaskScheduler
{
protected override IEnumerable<Task> GetScheduledTasks()
{
return null;
} protected override void QueueTask(Task task)
{
var thread = new Thread(() =>
{
TryExecuteTask(task);
}); thread.Start();
} protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
throw new NotImplementedException();
}
}
}

看到没有,自定义Task就是这么简单,其实自定义操作中最重要的就是其中的QueueTask方法,接下来我可以用windbg观察一下,确实是工作线程,而不是

线程池,没骗你~~~

好了,本篇就说到这里,希望对你有帮助。

用惯了Task,你应该也需要了解它的内部调度机制TaskScheduler的更多相关文章

  1. [.net 多线程]Task

    C# 异步编程Task整理(一) c# .Net并行和多线程编程之Task学习记录! .NET 实现并行的几种方式(一) Dispatcher介绍 [C#学习笔记]使用C#中的Dispatcher 用 ...

  2. 大话Spark(9)-源码之TaskScheduler

    上篇文章讲到DAGScheduler会把job划分为多个Stage,每个Stage中都会创建一批Task,然后把Task封装为TaskSet提交到TaskScheduler. 这里我们来一起看下Tas ...

  3. .Net多线程编程—任务Task

    1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...

  4. .NET Task揭秘(一)

    Task为.NET提供了基于任务的异步模式,它不是线程,它运行在线程池的线程上.本着开源的精神, 本文以解读基于.NET4.5 Task源码的方式来揭秘Task的实现原理.   Task的创建 Tas ...

  5. 实现基于Task的异步模式

    返回该系列目录<基于Task的异步模式--全面介绍> 生成方法 编译器生成 在.NET Framework 4.5中,C#编译器实现了TAP.任何标有async关键字的方法都是异步方法,编 ...

  6. 【C#】线程之Task

    Task开启线程 有两种启动方式: 1.构造创建线程,然后启动 var taskForAction = new Task(() => { //do something }); taskForAc ...

  7. MapReduce作业的map task和reduce task调度参数

    MapReduce作业可以细分为map task和reduce task,而MRAppMaster又将map task和reduce task分为四种状态: 1.pending:刚启动但尚未向reso ...

  8. 【Hadoop代码笔记】Hadoop作业提交之TaskTracker获取Task

    一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobClient提交的作业,并进行初始化.本文着重描述,JobTracker如何选择作业 ...

  9. Task的运行过程分析

    Task的运行过程分析 Task的运行通过Worker启动时生成的Executor实例进行, caseRegisteredExecutor(sparkProperties)=> logInfo( ...

随机推荐

  1. Visual Studio 2017正式版安装

    Visual Studio号称宇宙第一IDE, 2017年3月7日强大的微软帝国时隔两年多终于发布新一代IDE Visual Studio 2017.支持的功能简直不能太多,详情移步:https:// ...

  2. 一段获取app性能指标的py脚本

    #coding:utf-8 import os import timeimport datetimeimport subprocess ActivityManager = 'homepage.Main ...

  3. BananaPi python-Mysql 操作库

    BananPi python-Mysql 操作库 1.首先mysql.python环境安装 2.下载MySQL-python-1.2.3.tar.gz 并解压 tar xfz MySQL-python ...

  4. python+request接口自动化框架

    python+request接口自动化框架搭建 1.数据准备2.用python获取Excel文件中测试用例数据3.通过requests测试接口4.根据接口返回的code值和Excel对比 但本章只讲整 ...

  5. 一切app源于生活 用于生活 一个利于生活的app——利生活

    现在的app软件可以说 各行各业都基本达到饱和阶段 因为智能手机时代让我们的世界缩小了十倍百倍甚至千倍,我们可以足不出户知天下可以足不出户的去购物. 既然app利于生活 那么今天我所要开发的一个app ...

  6. pycharm社区版无database 解决方法

    第一步,点击file/setting/plugins 如下图所示 第二步,搜索database 安装database Nivagator 并Apply 第三步,新建数据库连接,open sql con ...

  7. 关于OOCSS的一点思考

    关于面向对象,自己是很熟悉了,不能说代码实际开发效果有多好,但是这个概念确实经常见,那么到底什么是面向对象? 面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物---百度 ...

  8. iOS开发之Xib和storyboard对比

    相同点: (2)都用来描述软件界面 (2)都用Interface Builder工具来编辑 不同点: (1)Xib是轻量级的,用来描述局部的UI界面 (2)Storyboard是重量级的,用来描述整个 ...

  9. Spring初识(通过小实例清晰认识Spring)

    1.spring架构: spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,iba ...

  10. vue2.0自定义指令的使用方法

    感觉2.0好坑啊,自定义指令和1.0完全不一样,并且文档写得也不太清晰,下面是我写得一个demo,希望帮助大家更好地理解自定义指令 <!DOCTYPE html> <html lan ...