专栏首页01ZOO工作流和状态机
原创

工作流和状态机

起源

因为工作相关的一些原因,最近开始看一些工作流的框架或者产品,有兴趣的可以看我这篇文章。任务流是一种很常见的任务组织形式:

graph LR
Start-->Step1
Step1-->Step2
Step2-->End

这种例子充斥我们的生活,比如订单系统,Hr系统,审批系统,CI/CD 系统,都是任务流的常见引用。

Dag

我们常见两种任务流的实现形式,一种是 DAG,dag 的表达的核心在于描述单个任务, 比如 描述一个 Task 他完成什么样的动作,以及他依赖什么样的动作,DAG 的描述和他的名字一样,缺陷在于不支持有环的任务流转(这一点只是为了简化,实际上也有办法实现)

TaskA:
    Actions:
    - 动作 A
    Dependencies:
TaskB:
    Actions:
    - 动作 B
    Dependencies:
    - TaskA
TaskC:
    Actions:
    - 动作 C
    Dependencies:
    - TaskA
    - TaskB

对这个 dag 进行简单的拓扑排序,就能得到他大概的执行流程, 下图为依赖图,首先会执行 TaskA,然后 TaskB,最后 TaskC

graph LR
TaskA-->TaskB
TaskA-->TaskC
TaskB-->TaskC

这个计算过程可以用下面的伪代码来简单描述,可以看出实现非常简单

For task in Tasks:
    if all_done(task's Dependencies):
        do(task)

状态机

状态机是实现任务流的另一种形式,表达的核心在于描述任务流转行为,即 Transition.

下面是一个 状态机的例子

Start: TaskA
TaskA:
    Actions:
    - 动作A
    Next:
        TaskB
TaskB:
    Actions:
    - 动作B
    Next:
        TaskC
TaskC:
    Actions:
    - 动作C
    Next:
        End

用一个简化的图表示:

graph LR
Start-->TaskA
TaskA-->TaskB
TaskB-->TaskC
TaskC-->End

对比

Dag

状态机

关注单个任务

关注状态流转

无环(也能实现,不过没这么直观)

可以简单的实现有环

实现简单

比较麻烦,需要记录任务当前状态

可以多个 Start

单个 Start

灵活性

Dag 串行表达,看上去不是很灵活, 而状态机表达更灵活,可以有环,可以任意流转。实际上并非如此:想象这样一种场景,如下图中的任务流程,我们需要新增一个任务 D,在任务 A 后执行,在任务 C 之前执行。对于这种变化,对 Dag 的修改是简单的,我们只需要新增一个节点就可以了, 同时修改节点 D 增加一个依赖:

TaskA:
    Actions:
    - 动作 A
    Dependencies:
TaskB:
    Actions:
    - 动作 B
    Dependencies:
    - TaskA
TaskC:
    Actions:
    - 动作 C
    Dependencies:
    - TaskA
    - TaskB
    - TaskD
TaskD:
    Actions:
    - 动作 D
    Dependencies:
    - TaskA

而对于状态机,同样的修改则更为麻烦,D 应该放在什么位置呢,首先考虑到 D 在 A之后执行,又在 D 之前,那么我们可以推理出:B和D可以并发执行, 然而这个结论并不那么显而易见,对于更负责的任务流转更是如此,涉及的修改也更多。新增一个流程对原先的状态机破坏,可能是颠覆性的。

Start: TaskA
TaskA:
    Actions:
    - 动作A
    Next:
        TaskB
Parallel:
    Tasks: 
        TaskB
            Actions:
            - 动作B
        TaskD
            Actions:
            - 动作D
    Next:
        TaskC
TaskC:
    Actions:
    - 动作C
    Next:
        End

可读性

状态机模型似乎可读性更高,因为 Dag 关注描述任务,一眼很难看出任务流转的模式,状态机直接描述任务流转,内部就可以很明显的看出每个 Stage。事实并非总是如此。想象一个任务流程有几百个任务, 这种情况下,即使是任务流所在的领域,比如 CRM 领域的专家也很难读懂整个任务流,这时候阅读当个任务的动作或者依赖,变成了一种更为简单直观的方式,通过好的前端实现,Dag 的可读性至少不会比 状态机差。

效率

不管是从实现相关系统的效率(Dag 的实现更为简单),还是从描述一个任务流程的效率(Dag 的描述更简单,状态机往往有更多概念,比如 并行,Map等),还是具体的运行效率(考虑上面的例子,确定两个任务可以并发执行,并不是一件容易的事情)Dag 都有相当的优势。

总结

最近的实现 Aws 的 statemachine spec,以及类似的 云厂商都推出了类似的状态机描述 spec,以及对应的实现。cncf 甚至推出了一个更复杂的实现。然而事实却没那么理想,各个云产商应该是跟随 AWS 做了一个错误的决策。

和这些产品相比,AWS 的一个老产品 Simple Workflow 的理念(DAG)则更优秀,不过由于 AWS 当年的实现过于抽象,这个产品也不是很成功,现在已经处于不再更新的状态(开源产品 Argo 有两种表达形态,既可以用 StateMachine,也可以用 Dag 表示)。但是未来的某一天,产品经理们可能会把它从垃圾堆里重新翻出来,因为他们最终发现,这才是正确的产品。

参考

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 常用算法整理

    王磊-AI基础
  • Prometheus TSDB

    写一般是对比如1000个series 同时进行采集,所以他是纵向的。磁盘随机写效率低、SSD 写放大问题  →  顺序写 和 批量写 是必然选择 (sequen...

    王磊-AI基础
  • Go语言各版本特性回顾(1.5-1.14)

    如何优化这两项体验的同时不引入过多复杂度是一个重要的难题(同时要兼容 go 1.x ),毕竟在我看来 go 语言最大的优势就是:“少即时多”。个人觉得:编译器实...

    王磊-AI基础
  • scikit-learn 之人脸数据集

    最近我要对人脸数据进行特征提取,免不了获取人脸数据集,第一次运行加载人脸数据集函数需要下载数据集下载好久,当然加速下载也是很简单的。

    不可言诉的深渊
  • 文本处理时需小心驶得万年船

    sra数据库的文件的srr开头的ID需要以gsm开通的id进行中转才能对应到真正的样本处理信息。

    生信技能树
  • Java 设计模式系列(3) —— 模板方法模式

    模板方法模式的定义: 定义一个操作算法的框架,将一些步骤延迟到子类中,使得子类可以不改变一个算法结构,即可重新定义该算法的某些特定步骤。

    求和小熊猫
  • 哪些产品经理认为很简单的功能,其实技术很难实现?

    在社交产品上看到一个有意思的话题:在产品看来很简单的需求,为什么在技术实现起来却很难?本是同根生相煎何太急。 第9条很搞笑; 1.-- 简单加一个在线聊天,最好...

    春哥大魔王
  • IDEA快捷键拆解系列(三):Edit篇

      以下是关于Edit导航项及其每一子项的拆解,其中,加粗部分的选项是博主认为比较重要的。

    happyJared
  • for循环+fork-join_none结构的坑,你有注意到吗?

    fork-join_none相信大家应该熟悉了,新来的朋友可以回顾下jerry之前的文章,就是之前jerry提到的那个“暴脾气”的哥们,他不会去等别人,直接会着...

    IC验证
  • PHP+MYSQL购物车逻辑推理

    用户7873631

扫码关注云+社区

领取腾讯云代金券