前言:
自从接触异步(async await Task)操作后,始终都不明白,这个Task调度的问题。
接触Quartz.net已经很久了,只知道它实现了一套Task调度的方法,自己跟着Quartz.net源代码写了遍,调试后我算是明白了Task调度的一部分事()。
(资料图片仅供参考)
春风来不远,只在屋东头。
理解Task运行,请参考大佬文章 https://www.cnblogs.com/artech/p/task_scheduling.html ,推荐大佬的书。
直到我看Quartz.net源代码中的任务调度 “QueuedTaskScheduler”,我才搞明白了,如何写一个简单的任务调度器,或者说线程如何执行代码,才不会造成死循环,CPU吃满等问题,下面代码有的直接从quartz.net copy过来的。
BlockingCollection类
微软文档 https://learn.microsoft.com/zh-cn/dotnet/standard/collections/thread-safe/blockingcollection-overview
个人博客,中文解释通俗易懂 https://www.cnblogs.com/gl1573/p/14595985.html
BlockingCollection 提供一个很重要的“阻塞”功能。
TaskScheduler类
TaskScheduler 直译过来:表示一个对象,该对象处理将任务排队到线程上的低级工作。
该类为抽象类,其真正意义在于“对Task任务的编排”
基于TaskScheduler类实现自定义的“Task队列调度器”
源代码,我的仓库 https://github.com/qiqiqiyaya/Learning-Case/tree/main/TaskScheduler/AspNet6TaskScheduler
1.定义一个存储Task的队列容器,使用BlockingCollection容器来添加Task,为什么使用BlockingCollection,后面会解释
/// The collection of tasks to be executed on our custom threads. private readonly BlockingCollection _blockingTaskQueue; 2.定义CancellationTokenSource变量,用于释放。通常就是调用 CancellationToken.ThrowIfCancellationRequested() ,抛出一个 “OperationCanceledException”的异常,使正在执行的Task任务停止。
3.创建Thread数组,用于存储创建出的Thread
/// The threads used by the scheduler to process work. private readonly Thread[] _threads;4.自定义一个类QueuedTaskScheduler,继承 “TaskScheduler”,“IDisposable”
public class QueuedTaskScheduler: System.Threading.Tasks.TaskScheduler, IDisposable实现构造函数
public QueuedTaskScheduler(int threadCount) { _threadCount = threadCount; _blockingTaskQueue = new BlockingCollection(); // create threads _threads = new Thread[threadCount]; for (int i = 0; i < threadCount; i++) { _threads[i] = new Thread(ThreadBasedDispatchLoop) { Priority = ThreadPriority.Normal, IsBackground = true, Name = $"threadName ({i})" }; } // start foreach (var thread in _threads) { thread.Start(); } } 在构造函数中创建,并启动“Thread”,构造函数接收一个“线程数量的参数”,控制开启的线程数。
Thread中实现的委托为“ThreadBasedDispatchLoop”,其表达意思是“基于循环的调度”。
5.重点来了,具体看下“ThreadBasedDispatchLoop”方法的实现
ThreadBasedDispatchLoop实现
/// The dispatch loop run by all threads in this scheduler. private void ThreadBasedDispatchLoop() { _taskProcessingThread.Value = true; try { // If a thread abort occurs, we"ll try to reset it and continue running. while (true) { try { // For each task queued to the scheduler, try to execute it. foreach (var task in _blockingTaskQueue.GetConsumingEnumerable(_disposeCancellation.Token)) { TryExecuteTask(task); } } catch (ThreadAbortException) { // If we received a thread abort, and that thread abort was due to shutting down // or unloading, let it pass through. Otherwise, reset the abort so we can // continue processing work items. if (!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload()) {#pragma warning disable SYSLIB0006 Thread.ResetAbort();#pragma warning restore SYSLIB0006 } } } } catch (OperationCanceledException) { // If the scheduler is disposed, the cancellation token will be set and // we"ll receive an OperationCanceledException. That OCE should not crash the process. } finally { _taskProcessingThread.Value = false; } }在外层套一层try catch捕获 CancellationTokenSource 变量,取消操作(CancellationTokenSource.Cancel())产生的异常,并且忽略该异常。
其中使用while(true),无限循环执行,?????奇了怪了,为什么以前写代码时,while(true)写了,会直接把CPU吃满,程序搞奔溃呢????
关键点就在于
当_blockingTaskQueue.GetConsumingEnumerable(_disposeCancellation.Token)执行时,如果_blockingTaskQueue容器中没有元素时,执行就会被“阻塞”,这种阻塞不会造成或者造成很小的资源浪费。
当_blockingTaskQueue有值时,阻塞就会停止,_blockingTaskQueue.GetConsumingEnumerable(_disposeCancellation.Token)执行,返回一个Task对象,然后开始执行 TryExecuteTask(task) ,执行Task。
6.继承 “TaskScheduler”后需要实现的几个方法
GetScheduledTasks
protected override IEnumerable? GetScheduledTasks() { return _blockingTaskQueue.ToList(); } GetScheduledTasks 返回需要被调度的 Tasks
QueueTask
protected override void QueueTask(Task task) { // QueuedTaskScheduler 释放时,禁止向队列中添加Task if (_disposeCancellation.IsCancellationRequested) { throw new ObjectDisposedException(GetType().Name); } _blockingTaskQueue.Add(task); }QueueTask 将排队等候的Task加入到 “_blockingTaskQueue”队列变量中
TryExecuteTaskInline
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) { // If we"re already running tasks on this threads, enable inlining return _taskProcessingThread.Value && TryExecuteTask(task); }意思是,参数task是否在此线程上运行,请查看ThreadBasedDispatchLoop方法。
“ThreadLocal
自此自定义“Task调度器”完成。
启动,运行QueuedTaskScheduler
1. 创建 QueuedTaskScheduler ,其中用于执行Task的线程数为 1
2.创建 Task ,并将其加入到指定的 Task调度器中。
3.调试一下
A. 创建QueuedTaskScheduler ,创建 线程 “Thread” ,并启动线程
B. 调试过程
当_blockingTaskQueue没有Task时,执行到_blockingTaskQueue.GetConsumingEnumerable(_disposeCancellation.Token) 就会阻塞。
自此 自定义TaskScheduler完成。
我的源代码 https://github.com/qiqiqiyaya/Learning-Case/tree/main/TaskScheduler/AspNet6TaskScheduler
关键词:
推荐内容
- 世界热点评!自定义一个简单的Task调度器
- 台州路桥区中央山绿轴区块(路北街道)拆
- 她字怎么组词是什么 她字怎么组词|讯息
- 世界热点!零式战斗机(零式舰载战斗机)
- 关于郑爽新剧官方道歉是怎么回事 郑爽新
- 天天最资讯丨深交所:做好全面实行股票发
- 环球观点:迦南智能:公司基于对充电桩产
- 江西上饶150万亩油菜迎丰收 农机助力收割忙
- 里夫斯:八村塁的体型给球队带来了一些优
- 世界快播:梦幻联动!朱一龙与戛纳影帝麦
- 巡回考编路
- 美国政府最早6月1日耗尽现金?经济学家:
- 沪指震荡跌0.23% 军工、互联网电商板块
- 全球播报:dnf宝珠收集箱怎么弄_dnf宝珠收
- 当前热讯:获利指数计算例题 获利指数
- 如何看待券商转债价值:“中特估”长坡厚
- 孕妇可以吃板栗饼吗早期
- 障用户知情同意权有缺欠 “易行通ETC”
- 世界今头条!博实股份:5月16日融资买入2
- 俄方称摧毁乌军“爱国者”系统,美官员承
- 田径街头巡回赛朱亚明夺冠|世界观点
- 2023浙江杭州市富阳区考试录用公务员拟录
- 留给美国的时间真不多了
- 【全球聚看点】一个赛季才出场13分钟!哈
- 魔声入耳式有线耳机享受满200减30优惠-焦
- 我国科学家揭示杂种优势“聚合”新机制_
- 发票抵扣联遗失怎么处理2020年新规_增值
- 应民心、解民忧、惠民生……市人社局开展
- 兔宝的歌单喔~ 持续更新中。。。 今日最新
- 新动态:i8258涓嬭浇_i8258
- 【环球快播报】江浙沪指的哪几个地方_江
- 2023年南陵县事业单位笔试成绩查询
- 苹果怎么处理未受信任的企业级开发者_苹
- 百度第一季度净利润增长48%至57亿元 百
- 狗驾?美国一司机涉嫌酒驾被拦截 竟想让
- 高中社会实践活动例子 什么是缩聚反应特
- 7238万元 前4个月马鞍山市学前教育投入
- 仰望U8、新款宋PLUS领衔,三款比亚迪重磅
- 中建八局发展建设公司联想创新科技园项目
- 淅川县长王兴勇赴上海天贶新能源科技有限
- 热推荐:2023年临床执业(助理)模考试题含
- 我的世界胡萝卜怎么得|每日资讯
- 4月份国民经济运行延续恢复向好态势 多
- 热文:新的生化危机4重制镜头展示了第5章
- 世界微资讯!地下城附魔师怎么快速升级_
- 环球焦点!省第十届民族运动会竞赛场地在
- 全国百强!福州9个县(市)区上榜
- 能否并购伊莱克斯要看美国脸色 但美的这
- 环球观点:汕头旅游地图_汕头旅游
- 世界焦点!记者手记:在西安,感受千年古
- 头条焦点:萧山掀起全民“花式”学英语热
- 一个月能瘦20斤吗_运动减肥一个月瘦20斤
- 网球!罗马大师赛:阿尔卡拉斯爆冷出局,
- 半幅式方向盘取消上公告?网友拍手叫好
- 老里曾说快船不会赢&没有合作?雷迪克:
- 最新:如何压缩PPT文件大小(如何压缩ppt
- 2023青岛第一海水浴场什么时间开放?
- 国家能源局:4月份全社会用电量同比增长8
- 意大利留学申请条件和费用(意大利留学申
- 全球短讯!万润股份:接受安信证券等机构
- 田径街头巡回赛朱亚明夺冠|世界观点
- 2023浙江杭州市富阳区考试录用公务员拟录
- 留给美国的时间真不多了
- 【全球聚看点】一个赛季才出场13分钟!哈
- 魔声入耳式有线耳机享受满200减30优惠-焦
- 我国科学家揭示杂种优势“聚合”新机制_
- 发票抵扣联遗失怎么处理2020年新规_增值
- 应民心、解民忧、惠民生……市人社局开展
- 兔宝的歌单喔~ 持续更新中。。。 今日最新
- 新动态:i8258涓嬭浇_i8258
- 【环球快播报】江浙沪指的哪几个地方_江
- 2023年南陵县事业单位笔试成绩查询
- 苹果怎么处理未受信任的企业级开发者_苹
- 百度第一季度净利润增长48%至57亿元 百
- 狗驾?美国一司机涉嫌酒驾被拦截 竟想让
- 高中社会实践活动例子 什么是缩聚反应特
- 7238万元 前4个月马鞍山市学前教育投入
- 仰望U8、新款宋PLUS领衔,三款比亚迪重磅
- 中建八局发展建设公司联想创新科技园项目
- 淅川县长王兴勇赴上海天贶新能源科技有限
- 热推荐:2023年临床执业(助理)模考试题含
- 我的世界胡萝卜怎么得|每日资讯
- 4月份国民经济运行延续恢复向好态势 多
- 热文:新的生化危机4重制镜头展示了第5章
- 世界微资讯!地下城附魔师怎么快速升级_
- 环球焦点!省第十届民族运动会竞赛场地在
- 全国百强!福州9个县(市)区上榜
- 能否并购伊莱克斯要看美国脸色 但美的这
- 环球观点:汕头旅游地图_汕头旅游
- 世界焦点!记者手记:在西安,感受千年古
- 头条焦点:萧山掀起全民“花式”学英语热
- 一个月能瘦20斤吗_运动减肥一个月瘦20斤
- 网球!罗马大师赛:阿尔卡拉斯爆冷出局,
- 半幅式方向盘取消上公告?网友拍手叫好
- 老里曾说快船不会赢&没有合作?雷迪克:
- 最新:如何压缩PPT文件大小(如何压缩ppt
- 2023青岛第一海水浴场什么时间开放?
- 国家能源局:4月份全社会用电量同比增长8
- 意大利留学申请条件和费用(意大利留学申
- 全球短讯!万润股份:接受安信证券等机构
- 中国驻日本大使吴江浩走访NHK会长稻叶延
- 天天资讯:可以说是自己身体很不好,经常
- Mysteel晚餐:央行定调最新货币政策,铁
- 重大疾病保险范围有哪些?有必要买吗?
- 鸡群一旦被呼吸道“缠上”,小则影响出栏
- 焦点短讯!21CC|肺癌患者5年生存率仅为1
- 世界要闻:美式校园电影风穿搭博主
- 长七总师:不久的将来中国人足迹一定会踏
- 环球看点!河南新乡辉县产地连翘走势稳定
- 每日看点!“北向互换通”今日开闸 金融
- 黄晓明监制主演新片《最后的真相》今日定
- 南宁白沙大道一辆吊车失控撞倒交通信息龙
- 微动态丨我,四岁儿子丢失,为寻子瘦了十
- “权”解旱塬渴|天天最新
- 瓯海区委书记曾瑞华督查2023数据安全发展
- 焦点滚动:队史第27冠,巴萨提前四轮赢得
- 超大国际邮轮“海洋光谱号”将于明年4月
- 天天亮点!重庆:188名科研人员入选顶岗
- 铜川药王山风景区官网_药王山风景区
- 杭州本地专升本院校排名 杭州有哪些专升
















