Skip to content

开发日志 0.0.9

十大才子之首 edited this page Jun 28, 2022 · 1 revision

混合任务

指的是将串行化任务和并行化任务组合在一起的一组任务。

  1. 串行化任务侧重于一排任务依次执行,其中存在前后关联
  2. 并行化任务侧重于多个任务同时进行,互相独立
  3. 混合任务将两者结合,寻找多个并发执行的任务的交互点

实际案例

假如一个小组的战士共同完成一项任务,假设一个小组六个人,那么每个人会负责任务的一部分,示意图如下:

img

首先需要一个开始节点,这可以是无任何意义的空节点,也可以是一个真正的开始节点,总之是一切任务的源头,从开始节点分裂出了B,C,E三个节点,这三个节点是好不相关的三个任务,但是新的任务D必须在B和C完成后才可以进行,这是有严格顺序性的,顺序性是为了让执行结果正确和任务可以顺序进行。

问题一

Multi的运行机制是这样的:当一个任务需要执行时,Multi为其分配一个线程和一块内存地址result,任务完成后任务线程会把结果写入到resulr中,当调用方需要获取结果时直接去拿result中的结果即可。

所以对于上图中所示的任务可以这样为其分解:

    1. 找尾结点,尾结点可能有多个,上图中的尾结点为G
    2. 获取G的结果,G的运行结果就是最终的结果,但是G的结果需要得到E和F的结果,如果E和F已经完成,那么是可以直接在其result中获取到结果的
    3. E是独立节点,不需要依赖其他的任务
    4. F的完成需要D的执行结果,以此类推D需要B和C的结果
    5. 最终G执行完成

看起来并不复杂,但是其中却存在很多模糊的地方,比如G节点和D节点的入参,两个前置任务还好,如果存在多个前置任务,就需要多个入参,这样是很难为其动态分配的,其中也包括了参数的顺序问题,即前置节点的顺序,调用者需要花费额外的精力处理参数这显然是不方便的。

解决方案

通过共用内存空间的方式进行解决,不为任务设置参数,通过对Multi进行join来判断前置任务是否完成,如果需要用到参数的地方则需要在前置节点中为其准备好,以方便在后置任务中获取。

问题二

任务的装配,比如上图中的G节点,要如何说明他需要E和F作为前置节点?这涉及到任务的装配顺序,如果是正序装配则从头节点开始装配到B,此时说明B的后置节点是D,装配到C时C也需要指明后置节点是D,此时D需要暴露给C说明D已被装配,不然C就会重新装配一个和D相同的任务,倒序装配同样存在这样的问题。

解决方案

命名,通过对任务进行命名从而解决任务的装配问题,这需要使得任务的名称唯一,通过hash表存储。

此解决方案较笨重,但是绝对灵活

混合任务的实现

结果使用一个泛型来指定。

此外还包含四个集合:

  1. mixTasks,任务集合,存放已经被处理的任务
  2. taskName,任务的名称,用于去重
  3. tailMixTasks,尾结点集合,快速确定尾结点
  4. waitForTask,等待集合

每次加入新的任务时,先去判断其前置任务是否执行完成,如果执行完成的话才会把当前任务封装放入任务集合,并处理尾结点集合,如果前置任务没有执行完,则进入等待集合,等待下一个任务再次进行判断,或者等待混合任务最终执行。

这样处理的不方便之处是异常节点,每次加入一个新的任务都有可能验证之前的任务,如果此时没有加入异常节点又恰好存在异常,则任务将直接出现异常。

如此一来这种方式就行不通了,需要换一种。

对任务的装配进行滞后处理,加入到混合任务时不再判断是否可以加入,任务的装配统一放在最终阶段。

为了优化任务,不存在前置节点的任务直接装配

等待集合为什么不是队列?

等待集合中的相邻两个元素可能不存在任务关联,任务和各自的前置任务是通过一个标识唯一确定的,结构相对松散,并不适合使用队列

结语

并行任务的索引重复策略,混合任务前置节点添加策略