HTML5技术

用惯了Task,你应该也需要了解它的内部调度机制TaskScheduler - 一线码农

字号+ 作者:H5之家 来源:H5之家 2017-04-29 10:01 我要评论( )

平时我们在用多线程开发的时候少不了Task,确实task给我们带来了巨大的编程效率,在Task底层有一个TaskScheduler,它决定了task该如何被调度,而 在.net framework中有两种系统定义Scheduler,第一个是Task默认的ThreadPoolTaskScheduler,还是一种就是Synch

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

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

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

 

一: ThreadPoolTaskScheduler

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

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

QueueTask(Task task) 2 { 3 if ((task.Options & TaskCreationOptions.LongRunning) != TaskCreationOptions.None) 4 { 5 new Thread(ThreadPoolTaskScheduler.s_longRunningThreadWork) 6 { 7 IsBackground = true 8 }.Start(task); 9 return; 10 } 11 bool forceGlobal = (task.Options & TaskCreationOptions.PreferFairness) > TaskCreationOptions.None; 12 ThreadPool.UnsafeQueueCustomWorkItem(task, forceGlobal); 13 }

 

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

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

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

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

Main(string[] args) 2 { 3 var task = Task.Factory.StartNew(() => 4 { ); 6 }, TaskCreationOptions.LongRunning); 7 8 Console.Read(); 9 }

 

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

应该就非常明朗了。

Main(string[] args) 2 { 3 var task = Task.Factory.StartNew(() => 4 { ); 6 }); 7 8 Console.Read(); 9 }

 

 

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

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

 

二:SynchronizationContextTaskScheduler

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

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

QueueTask(Task task) 2 { 3 this.m_synchronizationContext.Post(SynchronizationContextTaskScheduler.s_postCallback, task); 4 }

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

Post(SendOrPostCallback d, object state) 2 { 3 ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state); 4 }

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

button1_Click(object sender, EventArgs e) 2 { 3 Task task = Task.Factory.StartNew(() => 4 { Thread.Sleep(10000); 7 8 }).ContinueWith((t) => 9 { ; 11 }, TaskScheduler.FromCurrentSynchronizationContext()); 12 }

 

 

三:自定义TaskScheduler 

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

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

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

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 【大前端之打通账号系统】passport应该如何落地? - 叶小钗

    【大前端之打通账号系统】passport应该如何落地? - 叶小钗

    2016-07-27 10:00

  • 小公司的前端应该怎么做? - 叶小钗

    小公司的前端应该怎么做? - 叶小钗

    2016-05-15 18:00

  • 一个优秀的程序员应该如何提高工作效率? - cherry0327

    一个优秀的程序员应该如何提高工作效率? - cherry0327

    2016-04-16 18:00

  • 面试感悟----一名3年工作经验的程序员应该具备的技能 - 五月的仓颉

    面试感悟----一名3年工作经验的程序员应该具备的技能 - 五月的仓颉

    2016-03-12 17:00

网友点评
/