今天, 是系列文的小小里程碑, 我们终於在今天找出了 task 的其中一种非同步演算法。
他被用在让 Task 接着执行下一个任务的 method 中。
查看昨天提到执行这件事的 method ITaskCompletionAction.Invoke(this)
// Interface to which all completion actions must conform.
// This interface allows us to combine functionality and reduce allocations.
// For example, see Task.SetOnInvokeMres, and its use in Task.SpinThenBlockingWait().
// This code:
// ManualResetEvent mres = new ManualResetEventSlim(false, 0);
// Action<Task> completionAction = delegate { mres.Set() ; };
// AddCompletionAction(completionAction);
// gets replaced with this:
// SetOnInvokeMres mres = new SetOnInvokeMres();
// AddCompletionAction(mres);
// For additional examples of where this is used, see internal classes Task.SignalOnInvokeCDE,
// Task.WhenAllPromise, Task.WhenAllPromise<T>, TaskFactory.CompleteOnCountdownPromise,
// TaskFactory.CompleteOnCountdownPromise<T>, and TaskFactory.CompleteOnInvokePromise.
internal interface ITaskCompletionAction
{
void Invoke(Task completingTask);
}
发现其原来仅仅只是一个介面, 本身的功能是由他的继承者实践的,
此时非常巧合的(一点都不巧 XD )我想起了在 Day7 时提到的 Task.WhenAll
流程
当 task 未完成, 就把
WhenAllPromise
的 reference 挂载到 未完成的 task 的连续任务区(这个名词是我自己取的 XD )
而在 WhenAllPromise
中恰好有一个 method 叫 Invoke
其功能是 atomic 的减少 WhenAllPromise
中未完成的任务数量, 且当数量归零, 结束WhenAllPromise
和回传结果。
然後又发现了, 原来 WhenAllPromise
正式继承自ITaskCompletionAction
自此我们拚完了 WhenAllPromise
的最後一块拼图, 也解释了让 Task 接着执行下一个任务的方法。
接着会抽象的解释其流程, 再利用 WhenAllPromise
做举例。
抽象流程:
资料结构
当希望某个资料结构所要执行的事务, 可以被放到其他某个任务完成後执行时, 就将那个事务打包成名为 Invoke
的方法, 放在资料结构里。
使用端 (假设 Thread 具有足够承载力, 不需要把後续任务放入 TP , 可在本身 thread 继续执行)
当调用某"资料结构"执行某事务, 发现该事务目前无法完成, 需要留到某其他任务完成後执行, 就将该资料结构推入 Task 中的连续任务区, 在 Task 将其本身的任务完成後, 会依序触发 Task 的连续任务区里的资料结构的 Invoke
方法。
值得注意的是每种 CASE 有其对应的的细节, 不过概略上的逻辑差不多, 所以我仅以其中一种为例。
实际流程举例 :
Task.WhenAll
完整流程:
当 Task.WhenAll( taskList )
调用後执行动作
taskList = 待完成任务列表, 我自己命名的变数
WhenAllPromise
物件, 且传入 taskListWhenAllPromise
物件中WhenAllPromise
内部执行依序扫描 taskList 内的 taskWhenAllPromise
有可能被挂载到别的 task 执行, 就会被视为 multi-thread )WhenAllPromise
的 reference 挂载到 未完成的 task 的连续任务区(这个名词是我自己取的 XD )WhenAllPromise
内的未完成任务数量为0, 表示任务全部完成, 当即设置回传变数, 与进行回传。WhenAllPromise
有在上面的第 5 步挂载到别的 task。WhenAllPromise
不会结束。Task.WhenAll( taskList )
留在原地闲置。WhenAllPromise
挂载到的任务完成, 表示当初传入的 taskList 的未完成任务数量又减了一所以在阶段结束时执行被挂载的 WhenAllPromise
中的Invoke
方法。Invoke
方法会 atomic 的把未完成任务数量减 1 , 且若减完 1 未完成任务数量为 0 时, WhenAllPromise
当即设置回传变数, 与进行回传。Task.WhenAll( taskList )
顺利回传 taskList 执行结果, 主程序继续往下运行。这真的是一种有很有趣的演算法, 当你以非同步的方式要进行某件任务, 却发现这个任务被别的任务阻塞无法完成, 就直接把自己挂载到阻塞你的对象身上, 并且要求他在自己完成後, 接着执行挂载到自己身上的任务。
以上做法其实就是一种初步的 schedule 演算法, 就如同我在第二天的 sample , 一个 httpServer ,
可以发现我虽然创建了无数个 thread 来处理 request 但是大多数的 thread 其实只是在无限回圈中空转等待 request 的到来, 这其实非常耗费资源, 我当时提到, 应该要有种 schedule 的方法把没在用的 thread 送入 闲置状态, 而我们今天读到的就是一种方法。
若是不使用这种演算法, 运行 Task.WhenAll( taskList )
的 thread 也需要进入一个无限回圈, 需要不断的检测他追踪的任务是否已经完成, 而如今, 直接将 thread 闲置, 让每个任务完成时主动进行通知, 大大提高了效能。
明天, 轮到让 Task 进入 TP 中的 method ThreadPool.UnsafeQueueCustomWorkItem
终於可以开始聊 TP 了!
明天见 !
绑定的资料和画面上的元素不相等 enter()函式—没放入元素的资料 先看以下程序码 <bod...
今日题目 题目连结:965. Univalued Binary Tree 题目主题:Tree, De...
开心,终於正式进入 Vue 的介绍了~ 在了解 Vue 的写法前,有个重要的观念必需去了解,那就是 ...
Day29 - kali 0x4 Metasploit 前言 昨天提完破密工具之後,今天来讲讲这个e...
今天接续昨天的内容,把会员管理页面做一个收尾 使用者列表 这边可以用 ViewModel 来呈现使用...