[Day 14] .Net 非同步概念整理

前言

本来只是想简单带过 .Net , 但不知不觉就写了一大堆, 觉得内容有些混乱, 就在今天花些时间把这些篇的内容作个总整理吧。

Task 的底层

  1. Task 可以被视为 ThreadPool 的介面, 非同步的 Task 就直接把任务丢给 ThreadPool 後继续往下做, 同步的 Task 则是任务丢给 ThreadPool 後闲置自己, 等待 ThreadPool 把任务完成。
  2. Task 被投入要执行的任务後会有以下行为
    1. 将当前 thread 的内容记录, 之後才能进行 Thread 切换
    2. 依情况设置排程器, 本篇有提到两种排程器, 分别是 SynchronizationContextTaskScheduler 和 threadpool
    3. 若是排程器选择 threadpool 且检测为超长任务, 用 Thread 创建一个新 thread 执行
    4. 若是排程器选择 threadpool 且检测不为超长任务, 把任务推入 Threadpool 执行
    5. 若是排程器选择 SynchronizationContextTaskScheduler , 把任务推入 Threadpool 执行, 但是使用一个外来方法要求 Threadpool 用同步方式执行此任务。 这就是一种 .Net 中 await 的实践方法
    6. 当 c~e 完成後, 执行 Task 中的连续任务区
    7. 若是正在执行的 thread 还能承载连续任务, 就直接接着执行连续任务
    8. 若是正在执行的 thread 还不能承载连续任务, 就直接把连续任务推入 Threadpool 执行
    9. 当连续任务区为空, Task 完成
  3. Threadpool 是一个早已被创建在系统中的资料结构, 其可以推入任务要求执行。参考 : https://zh.wikipedia.org/wiki/线程池
  4. 但 ThreadPool 只是一种概念, .Net 中的实践的方法是 workQueue , 且排程部分调用外部资源处理。参考 linux 的 workQueue : https://www.kernel.org/doc/html/v5.0/core-api/workqueue.html
  5. 简易描述 .Net 中的 ThreadPool 就是 :
    • .Net 会事先帮程序创建多个闲置的 thread, 每个 thread 内部都有存放区
    • .Net 还会创建一个特殊的排程 thread , 他会依照每个 thread 内部存放区的状态决定该唤醒哪个 thread ,该闲置哪个 thread。 所以没有任务的 thread 会闲置, 有任务的 thread 会被唤醒。
    • 每个醒着的 thread 就会执行自己内部存放区的任务。

本篇没提到的一些小知识

  1. C# 中的 async/await 是一种语法糖, 在编译後会被 Task 取代, 所以本篇文章才没有细讲他们。
  2. Thread 的功能是创建一条新 thread 来运行放入的任务, 和 Task 放入已经创建的 TP 是不同的。

利用 WhenAll 为 Sample 演示一群 Task 的调用

其中第 1 ,2 ,3 ,12 步新的, 读过前面的流程的读者, 只要看这三步就好。

taskList = 待完成任务列表, 我自己命名的变数

  1. 利用 Task.Run 打包多个任务
  2. 为每个任务创建 task 资料结构, 并且丢入 TP 交给他们执行
  3. 执行 WhenAll 方法, 且传入第2步创建的多个 task , 为了方面之後用 taskList 描述。
  4. 创建 WhenAllPromise 物件, 且传入 taskList
  5. 把 taskList 的长度(视为未完成任务数量)存在 WhenAllPromise 物件中
  6. WhenAllPromise 内部执行依序扫描 taskList 内的 task
  7. 当 task 已完成, 就把 未完成任务数量 减 1 ( 要 atomic , 因为 WhenAllPromise 有可能被挂载到别的 task 执行, 就会被视为 multi-thread )
  8. 当 task 未完成, 就把 WhenAllPromise 的 reference 挂载到 未完成的 task 的连续任务区(这个名词是我自己取的 XD )
  9. 当一次全部扫描结束, 若是 WhenAllPromise 内的未完成任务数量为0, 表示任务全部完成, 当即设置回传变数, 与进行回传。
  10. 有可能未完成任务数量没有归零, 表示 WhenAllPromise 有在上面的第 5 步挂载到别的 task。WhenAllPromise 不会结束。
  11. 此时执行 Task.WhenAll( taskList ) 留在原地闲置。
  12. 当被 WhenAllPromise 挂载到的任务被 Threadpool 完成, 其会接着运行被挂载的 WhenAllPromise 中的Invoke 方法。
  13. Invoke 方法会 atomic 的把未完成任务数量减 1 , 且若减完 1 未完成任务数量为 0 时, WhenAllPromise 当即设置回传变数, 与进行回传。
  14. 整个 Task.WhenAll( taskList ) 顺利回传 taskList 执行结果, 主程序继续往下运行。

明天进度

试着写文章後, 发现一些平常一下就过去的东西撰写出来却要很久, 更不要说要写得好了。

带来的结果就是必须删减内容以及进度赶不上预期 QQ

明天开始就进入後半部分了, 我们会试着读 node.js, 之所以要读 node 有几个原因, 最主要就是我是 node 後端, 对这个比较有兴趣。 其二是, 他的 schedule 部分也在 github 上很好找, 不会像 .Net 一样找不到, 不会有种意尤未尽的感觉。

为了帮助大家理解之後要读的 node.js , 会先开始聊一下 IOCP 和 epoll 等概念。


<<:  予焦啦!支援 RISC-V 权限指令与暂存器

>>:  谈谈 Log 的定义以及使用 - part1

[Day 27]从零开始学习 JS 的连续-30 Days---BOM-浏览器物件模型(上)

BOM ( Browser Object Model ) 浏览器物件模型(上) 常听到 JavaSc...

DAY4-比CS更好玩的CSS

前言: 昨天的进度中,我们大致完成了一个由HTML建构起来的网站,只是看起来真的是太阳春了。今天我...

DAY 03 SCSS ? SASS ?

SCSS 是什麽?跟 SASS 是什麽关系? 说到这两个看起来是一样的东西,但是每次教学文章又发现好...

D27 第十四周 (回忆篇)

支线任务:共笔部落格切版 礼拜一的时候终於把留言版做完了,接着是弄共笔部落格的文章列表样板,花了一两...

大共享时代系列_022_Twitch Plays (衆人同时用弹幕控制一个游戏角色)

同心协力操作一个游戏角色,怎麽那麽难?ヽ(≧Д≦)ノ 你都怎麽玩电玩呢? 独自玩闯关、模拟类游戏? ...