百度统计
一面之猿网
让这个世界,因为我,有一点点的不一样
纯序员给你介绍图化框架的简单实现——事件触发

大家好, 我是不会写代码却天天想着用户触达的纯序员——Chunel Feng。在之前的文章中,我们说过CGraph 是一个简单好用的DAG调度流图。注入到pipeline中的每个node,在所有依赖的node执行完毕之后,就会开始执行。这也是dag调度中,最常规的应用。

但是,这些设定,有一些情况是无法满足的。比如,我想每间隔一分钟,上报一下当前系统的状态。又或者,我想在特定的时刻(比如,进入某个判断分支的时候),上报某个具体的参数值。这是当前的dag调度机制,无法做到的。

今天,我们接着之前的话题,跟大家聊一下CGraph中新加入的触发机制,和一些新的实用功能。

定时触发

设想一种这样的情况哈,我在执行pipeline的过程中,随时可能出现意外。我需要添加一个看门狗机制,每隔一分钟,来输出一下系统的负载信息,从而在负载过高的情况下,可以告警出来。

这个时候,我们需要用到CGraph的 GDaemon 机制了。GDaemon的逻辑,实际上是在pipeline 运行的同时,在后台开启一个可设置时间的 timer,跟pipeline在两个不同的维度执行,跟pipeline不占用线程资源,但可以获取pipeline中所有的GParam信息。

这样说,可能有点抽象。直接上代码:

image

可见,在这个tutorial中,有一个 daemonTask逻辑 每间隔2s 就执行一次。当然了,在 GDaemon的方法中,还可以向GNode一样 ,通过 CGRAPH_GET_GPARAM 方法获取pipeline中的参数信息。或者是通过实现GTemplateDaemon<>的构造函数中,来实现配置参数的传递。

GDaemon比较适合用来做一些跟pipeline主流程无关,但是却需要反复执行的逻辑。比如,生成一些系统状态的时序数据,或者持续监控pipeline是否在运行等。

事件触发

除了定时触发逻辑之外,还有一种事件触发的逻辑。比如,当多个 node 执行到特定的分支逻辑的时候,需要同步/异步的触发一个特定的功能。这个时候我们如何操作呢?这里推荐用CGraph中提供的GEvent(事件)机制。

一共有三步:
1,实现事件类的具体功能
2,在节点中,需要执行的地方,调用 notify 接口,完成事件的同步/异步触发。
3,在pipeline 中注册一个具体类型的事件

废话不多说,直接来看代码:

// 实现具体的事件类
class MyPrintEvent : public CGraph::GEvent {
public:
    CVoid trigger(CGraph::GEventParamPtr param) override {
        CGRAPH_SLEEP_MILLISECOND(100)    // 留100ms的耗时,便于看出来同步/异步触发机制
        auto myParam = CGRAPH_GET_GPARAM_WITH_NO_EMPTY(MyParam, "param1")
        CGraph::CGRAPH_ECHO("----> trigger [%d] times, iValue = [%d]", times_++, myParam->iValue);
    }

private:
    int times_ = 0;
};

// 在节点中,通过key和type来触发事件
class MyEventNode : public CGraph::GNode {
public:
    CStatus run () override {
        CStatus status;
        CGraph::CGRAPH_ECHO("[%s], before event notify", this->getName().c_str());
        /**
         * 模拟在这里,触发一个 event信息,同名的事件被异步执行
         * 从打印结果可以看出,after event send 这条信息,提前执行
         * 执行的时候,和pipeline公用同一个线程池资源
         */
        notify("my-print-event", GEventType::ASYNC);

        CGraph::CGRAPH_ECHO("[%s], after event notify", this->getName().c_str());
        return status;
    }
};

// 第三步,在pipeline 中注册对应的事件,在node中的notify就可以触发对应的事件了
void pipeline() {
    GPipelinePtr pipeline = GPipelineFactory::create();
    GElementPtr a,b = nullptr;
    CStatus status;

    status += pipeline->registerGElement<MyEventNode>(&a, {}, "nodeA");
    status += pipeline->registerGElement<MyNode1>(&b, {a}, "nodeB");

    // 在pipeline中添加一个事件信息,通过 notify("my-print-event")触发
    pipeline->addGEvent<MyPrintEvent>("my-print-event");
    pipeline->process();

    GPipelineFactory::clear();
}

大家可以会疑问,在node中触发一个方法,那自己随便封装一个函数,调用一下不就可以了么。为啥还要绕这一阵子,专门封装一个GEvent逻辑。

这里安利一下GEvent的好处:

  • 首先,GEvent机制使得逻辑更加清晰,调用方式更加规范,方便后期做进一步的扩展和优化。
  • 第二,GEvent机制复用了CGraph的pipeline内部的计算资源,用户不需要再关心开辟和释放线程的逻辑。相比自己开线程,有一些性能优势。
  • 还有,GEvent机制提供了一个位置,可以根据需要 获取/修改 pipeline中的任意多个参数的值,同时也便于内部参数追踪。这是自己写函数所不具备的功能,妙啊。

这样总结下来,GEvent比较适合处理在pipeline流程中,会多次在特定场景下执行的逻辑,且兼容了同步、异步两种模式。希望可以对您的项目有所帮助。

色图你的色图

在新版本的CGraph中,我们提供了英文版本的readme,再也不是awesome-cpp榜单中,唯一一个没有英文readme的项目了,哈哈。也正式启用了项目的中文名称:色丶图(Color Graph)

image-1678011326067

来自阿里的Ysi童鞋,实现了CGraph的可视化功能,使得色丶图变得跃然纸上。大家只需要在完成 pipeline 的算子注册逻辑之后,调用 pipeline->dump()方法,就可以在控制台上,得到一串信息。

image

把图中的信息,复制到 Graphviz Online 上,就能看到图的整体结构信息了

image-1678006860853

pipeline中的region,condition 等复杂逻辑,也可以被很好的展示,真正做到了所得及所见,有效避免了架构图来回调整,或者文档长时间未更新导致的前后不一。

同时,在最新版本中,还提供了参数链路追踪功能。打开之后,可以一键查看每个GParam的调用链路,方便做数据回溯和问题定位。也欢迎大家尝试使用。CGraph进入了v2.3.x 版本之后,主要在链路的可视化,问题追踪方面 做了一些功能优化,可能也是因为在工作中遇到的一些问题的,一些自己的思路和解法吧。

本章小结

很久没有写文章了。这期间,CGraph项目一直有断断续续的更新,其中也有叶神,风神等人的很多贡献。Ryan哥 更是在一个凌晨两点的 15分钟内,定位和解决了我一年都没能解决的问题,水平之高,难以想象。可能这就是大神和普通人之间的差距吧

在Mirror哥的帮助下,CGraph成功降级到了cpp11的语法,并且所有功能都适配了windows系统。相比于只支持cpp17的taskflow(我在github找到的绝大部分 类taskflow产品,都只支持cpp17或以上版本),在实际项目落地方面,有了质的飞跃。同时,我们也迎来了来自百度和腾讯等超一线大厂的第一批用户,这都是极好的背书,我们也会在工作之余,尽可能的做好配合和支持工作。希望可以互相学习,一起成长。

image-1678011160357

当聊到选用CGraph的原因和优势,很多人都会说到一个词:轻量级。是的,我们一直坚持,用原生cpp开发,没有引入任何的三方包。这的确使得我们在功能扩展上,受到了很大的限制。但高度简洁一致的代码风格,便于使用者根据实际需求做自己的扩展,且从根本上避免的各种蛋疼的环境和依赖问题。这也就是我们眼中的轻量级,但又不是那种轻飘飘的感觉。

接下来的业余时间,我们发力Python版本的开发和适配。希望可以在打通生态方面,有一个里程碑式的突破。届时,各种新玩法和新功能都会接踵而至。同时,为了保障工程自身的稳定迭代,对应的ci/ct也有专人设计和开发中。届时,CGraph工程下,又会多了一个很重要的新文件夹,哈哈。

目前,项目的官方贡献者已经有6位,后面5个人均大佬。也期待更多朋友的加入,一起共建赋能。下面是我的个人微信号,欢迎随时交流指教。

mmqrcode1602771241876

                                                          [2023.03.05 by Chunel]

推荐阅读


个人信息

微信: ChunelFeng
邮箱: chunel@foxmail.com
个人网站:www.chunel.cn
github地址: https://github.com/ChunelFeng

image