0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

workflow的任務(wù)模型

汽車電子技術(shù) ? 來源: 程序喵大人 ? 作者: 程序喵大人 ? 2023-02-21 14:05 ? 次閱讀

今天,想聊聊workflow這個開源項目。

關(guān)于workflow,我之前特意寫過一篇文章【推薦學(xué)習(xí)這個C++開源項目】。

今天還是想再啰嗦啰嗦,因為自己這一年也在帶團(tuán)隊從0到1做項目,需要負(fù)責(zé)整個項目的架構(gòu)設(shè)計、接口設(shè)計、模塊劃分等工作。

做了一段時間后再回過頭復(fù)盤一下,深知架構(gòu)設(shè)計、接口設(shè)計的重要性,也感受到了架構(gòu)設(shè)計的困難程度,編碼和設(shè)計相比,真的容易的多了。

然后自己又回頭來研究了一下workflow,想著學(xué)習(xí)下其他項目的設(shè)計理念,隨著自己研究的越來越深入,越來越感覺它的高端,對外暴露特別簡單的接口卻能完成非常復(fù)雜的功能。

上篇文章是基礎(chǔ)篇,主要向大家普及一下workflow的特點和作用,感興趣的朋友可以移步到那里哈。

本篇文章是進(jìn)階篇,主要就是想介紹下workflow的任務(wù)模型,其他的框架一般只能處理普通的網(wǎng)絡(luò)通信,而workflow卻特別適用于通信與計算關(guān)系很復(fù)雜的應(yīng)用。其實我最感興趣的是它的內(nèi)存管理機(jī)制,下面也會詳細(xì)介紹。

圖片

圖片

優(yōu)秀的系統(tǒng)設(shè)計

圖片

圖片

在作者的設(shè)計理念中:程序 = 協(xié)議 + 算法 + 任務(wù)流。

**協(xié)議:**就是指通用的網(wǎng)絡(luò)協(xié)議,比如http、redis等,當(dāng)然還可以自定義網(wǎng)絡(luò)協(xié)議,這里只需要提供序列化和反序列化函數(shù)就可以達(dá)到想要的效果。

算法: workflow提供了一些通用的算法,比如sort、merge、reduce等,當(dāng)然還可以自定義算法,用過C++ STL的朋友應(yīng)該都知道如何自定義算法吧,在workflow中,任何復(fù)雜的計算都應(yīng)該包裝成算法。

**任務(wù)流:**我認(rèn)為這應(yīng)該就是整個系統(tǒng)設(shè)計的核心,通過任務(wù)流來抽象封裝實際的業(yè)務(wù)邏輯,就是把開發(fā)好的協(xié)議和算法組成一個任務(wù)流程圖,然后調(diào)度執(zhí)行這個圖。

圖片

圖片

任務(wù)流

圖片

圖片

這里多聊聊任務(wù)流,在workflow中,一切業(yè)務(wù)邏輯皆是任務(wù),多個任務(wù)會組成任務(wù)流,任務(wù)流可組成圖,這個圖可能是串聯(lián)圖,可能是并聯(lián)圖,也有可能是串并聯(lián)圖,類似于這種:

圖片

也可能是這種復(fù)雜的DAG圖:

圖片

圖的層次結(jié)構(gòu)可以由用戶自定義,框架也是支持動態(tài)地創(chuàng)建任務(wù)流。

引用作者的一句話:

圖片

圖片

如果把業(yè)務(wù)邏輯想象成用設(shè)計好的電子元件搭建電路,那么每個電子元件內(nèi)部可能又是一個復(fù)雜電路。

workflow對任務(wù)做了很好的抽象和封裝。整個系統(tǒng)包含6種基礎(chǔ)任務(wù):通訊、文件IO、CPU、定時器、計數(shù)器。

workflow提供了任務(wù)工廠,所有的任務(wù)都由任務(wù)工廠產(chǎn)生,并且會自動回收。

大多數(shù)情況下,通過任務(wù)工廠創(chuàng)建的任務(wù)都是一個復(fù)合任務(wù),但用戶并不感知。例如一個http請求,可能包含很多次異步過程(DNS,重定向),內(nèi)部有很多復(fù)雜的任務(wù),但對用戶來講,這就是一次簡單的通信任務(wù)。

哪有什么歲月靜好,只不過是有人替你負(fù)重前行。workflow的一大特點就是接口暴露的特別簡潔,非常方便用戶的接入,外部接入如此簡單,肯定是將很多組合的邏輯都放在了內(nèi)部,但其實workflow項目內(nèi)部代碼結(jié)構(gòu)層次非常簡潔清晰,感興趣的朋友可以自己研究研究哈。

圖片

圖片

內(nèi)存管理機(jī)制

圖片

圖片

還有就是項目的內(nèi)存管理機(jī)制,workflow整個項目都遵循著誰申請誰釋放的原則,內(nèi)部申請的內(nèi)存不需要外部顯式釋放,內(nèi)部會自動回收內(nèi)存。

而且整個項目都沒有使用shared_ptr,那多個對象共同使用同一塊裸內(nèi)存,workflow是怎么處理的呢?

內(nèi)部為這種需要共享的對象各自維護(hù)一個引用計數(shù),手動incref和decref,至于為什么要這樣做,可以看看workflow美女架構(gòu)師的回答【https://www.zhihu.com/question/33084543/answer/2209929271】。

我總結(jié)了一下:

  • shared_ptr是非侵入式指針,一層包一層,而且為了保持shared_ptr覆蓋對象整個生命周期,每次傳遞時都必須帶著智能指針模板,使用具有傳染性,而且也比較麻煩。
  • shared_ptr引用計數(shù)的內(nèi)存區(qū)域和數(shù)據(jù)區(qū)域不一致,不連續(xù),緩存失效可能導(dǎo)致性能問題,盡管有make_shared,但還是容易用錯。
  • 手動為對象做incref和decref,使用起來更靈活,可以明確在引用計數(shù)為固定數(shù)字時做一些自定義操作,而且方便調(diào)試。因為手動管理對象的引用計數(shù),就會要求開發(fā)者明晰對象的生命周期,明確什么時候該使用對象,什么時候該釋放對象。
  • 如果使用shared_ptr可能會激起開發(fā)者的惰性,反正也不需要管理內(nèi)存啦,就無腦使用shared_ptr唄,最后出現(xiàn)問題時調(diào)試起來也比較困難。

那再深入源碼中研究研究,看看workflow是如何做到把對象指針給到外部后,內(nèi)部還自動回收的。

拿WFClientTask舉例說明一下,workflow中所有的Task都是通過Factory創(chuàng)建:

static WFHttpTask *create_http_task(const std::string& url,
                    int redirect_max,
                    int retry_max,
                    http_callback_t callback);


using WFHttpTask = WFNetworkTask;

template <class REQ, class RESP>
class WFClientTask : public WFNetworkTask {};

注意,create參數(shù)里有一個callback,workflow一定會執(zhí)行這個callback,然后內(nèi)部回收掉該WFClientTask占用的內(nèi)存,任何任務(wù)的生命周期都是從創(chuàng)建到callback函數(shù)結(jié)束。

它是怎么做到的?繼續(xù)看下WFClientTask的繼承層次結(jié)構(gòu):

template <class REQ, class RESP>
class WFClientTask : public WFNetworkTask {};


template<class REQ, class RESP>
class WFNetworkTask : public CommRequest {};


class CommRequest : public SubTask, public CommSession {};


class SubTask {
public:
  virtual void dispatch() = 0;
private:
  virtual SubTask *done() = 0;
protected:
  void subtask_done();
};

WFClientTask繼承于WFNetworkTask,WFNetworkTask又繼承于SubTask。

SubTask內(nèi)部有subtask_done()方法,看下它的實現(xiàn):

void SubTask::subtask_done() {
  SubTask *cur = this;
  ParallelTask *parent;
  SubTask **entry;


  while (1) {
    parent = cur->parent;
    entry = cur->entry;
    cur = cur->done();
    if (cur) {
      cur->parent = parent;
      cur->entry = entry;
      if (parent)
        *entry = cur;
      cur->dispatch();
    }
    else if (parent) {
      if (__sync_sub_and_fetch(&parent->nleft, 1) == 0) {
        cur = parent;
        continue;
      }
    }
    break;
  }
}

subtask_done()方法中會調(diào)用它的done()方法,然而這幾個方法都是virtual方法,看看WFClientTask是怎么重寫它們的:

template <class REQ, class RESP>
class WFClientTask : public WFNetworkTask<REQ, RESP> {
protected:
  virtual SubTask *done() {
    SeriesWork *series = series_of(this);
    if (this->state == WFT_STATE_SYS_ERROR && this->error < 0) {
      this->state = WFT_STATE_SSL_ERROR;
      this->error = -this->error;
    }
    if (this->callback)
      this->callback(this);
    delete this;
    return series->pop();
  }
};

子類重寫了done()方法,可以看到在它的實現(xiàn)里,觸發(fā)了callback,然后調(diào)用了delete this,釋放掉了當(dāng)前占用的這塊內(nèi)存。

那誰調(diào)用的done(),可以看下上面的代碼,subtask_done()會觸發(fā)done(),那誰觸發(fā)的subtask_done():

void CommRequest::dispatch() {
  if (this->scheduler->request(this, this->object, this->wait_timeout,
                 &this->target) < 0) {
    this->state = CS_STATE_ERROR;
    this->error = errno;
    if (errno != ETIMEDOUT)
      this->timeout_reason = TOR_NOT_TIMEOUT;
    else
      this->timeout_reason = TOR_WAIT_TIMEOUT;
    this->subtask_done();
  }
}

可以看到,dispatch()里觸發(fā)了subtask_done(),那誰觸發(fā)的dispatch():

template<class REQ, class RESP>
class WFNetworkTask : public CommRequest {
public:
  /* start(), dismiss() are for client tasks only. */
  void start() {
    assert(!series_of(this));
    Workflow::start_series_work(this, nullptr);
  }
};


inline void
Workflow::start_series_work(SubTask *first, SubTask *last,
              series_callback_t callback) {
  SeriesWork *series = new SeriesWork(first, std::move(callback));
  series->set_last_task(last);
  first->dispatch();
}

這里可以看到,Task的start()方法觸發(fā)start_series_work(),進(jìn)而觸發(fā)dispatch()方法。

總結(jié)一下:

● 步驟一

通過工廠方法創(chuàng)建WFClientTask,同時設(shè)置callback;

● 步驟二

外部調(diào)用start()方法,start()中調(diào)用Workflow::start_series_work()方法;

● 步驟三

start_series_work()中調(diào)用SubTask的dispatch()方法,這個dispatch()方法由SubTask的子類CommRequest(WFClientTask的父類)實現(xiàn);

● 步驟四

dispatch()方法在異步操作結(jié)束后會觸發(fā)subtask_done()方法;

● 步驟五

subtask_done()方法內(nèi)會觸發(fā)done()方法;

● 步驟六

done()方法內(nèi)會觸發(fā)callback,然后delete this;

● 步驟七

內(nèi)存釋放完成。

其實這塊可以猜到,想要銷毀自己的內(nèi)存,基本上也就delete this這個方法。

然而我認(rèn)為這中間調(diào)用的思想和過程才是我們需要重點關(guān)注和學(xué)習(xí)的,遠(yuǎn)不止我上面描述的這么簡單,感興趣的朋友可以自己去研究研究哈。

關(guān)于workflow還有很多優(yōu)點,這里就不一一列舉啦,它的源碼也值得我們CPP開發(fā)者學(xué)習(xí)和進(jìn)階,具體可以看我之前的文章。

發(fā)現(xiàn)workflow團(tuán)隊對這個項目相當(dāng)重視,還特意建了個QQ交流群(群號碼是618773193),對此項目有任何問題都可以在這個群里探討,也方便了我們學(xué)習(xí),真的不錯。項目地址如下:https://github.com/sogou/workflow,也可以點擊閱讀原文直達(dá)。

在訪問GitHub遇到困難時,可使用他們的Gitee官方倉庫:https://gitee.com/sogou/workflow。

項目也特別實用,據(jù)說搜狗內(nèi)外很多團(tuán)隊都在使用workflow。感覺這個項目值得學(xué)習(xí)的話就給人家個star,不要白嫖哈,對項目團(tuán)隊來說也是一種認(rèn)可和鼓勵。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 框架
    +關(guān)注

    關(guān)注

    0

    文章

    396

    瀏覽量

    17269
  • 網(wǎng)絡(luò)通信
    +關(guān)注

    關(guān)注

    4

    文章

    770

    瀏覽量

    29693
  • workflows
    +關(guān)注

    關(guān)注

    0

    文章

    6

    瀏覽量

    5909
收藏 人收藏

    評論

    相關(guān)推薦

    老生常談---一種裸奔多任務(wù)模型

    一種裸奔多任務(wù)模型一個網(wǎng)友的總結(jié):stateMachine + timerTick + queue。在RTOS環(huán)境下的多任務(wù)模型任務(wù)通常阻塞在一個OS調(diào)用上(比如從消息隊列取數(shù)據(jù))。外部如果想讓該
    發(fā)表于 12-08 10:13

    裸奔環(huán)境下的多任務(wù)模型

    對于簡單的嵌入式應(yīng)用多數(shù)裸奔就能解決,但寫出來的裸奔代碼質(zhì)量也由好壞之分。在網(wǎng)上看到了這樣一篇文字:上面說到了裸奔環(huán)境下的多任務(wù)模型 - stateMachine + timerTick
    發(fā)表于 01-21 07:41

    allegro中workflow manager求解

    allegro中analysis菜單下使用workflow manager,點擊start analysis后顯示implement analysis failed或者coupling analysis failed?
    發(fā)表于 03-07 22:02

    Stage模型深入解讀

    基于Stage模型開發(fā)應(yīng)用,下面將會從應(yīng)用組件、進(jìn)程模型、線程模型、任務(wù)模型、后臺運行機(jī)制、應(yīng)用配置文件6個方面進(jìn)行介紹。 1、組件模型
    發(fā)表于 03-15 10:32

    OPC 實時任務(wù)系統(tǒng)動態(tài)調(diào)度算法的研究與設(shè)計The Stud

    本文基于已有的OPC Server 實時任務(wù)模型,設(shè)計了處理混合任務(wù)集的動態(tài)調(diào)度算法(基于截止期優(yōu)先)和實現(xiàn)方式。該算法實現(xiàn)了對混合任集可調(diào)度性的判斷,可以完成有硬實時性要
    發(fā)表于 05-31 15:36 ?13次下載

    一種基于角色和任務(wù)的訪問控制模型

    在基于角色的訪問控制模型的基礎(chǔ)上引入了任務(wù)(task)和任務(wù)實例(task instance)的概念,建立了基于角色和任務(wù)的訪問控制模型(R
    發(fā)表于 08-05 16:30 ?8次下載

    控制系統(tǒng)中實時任務(wù)分析

    本文分析了控制系統(tǒng)任務(wù)的特點,給出了控制系統(tǒng)中各種實時任務(wù)模型。分析了控制系統(tǒng)性能與任務(wù)參數(shù)之間的關(guān)系,給出了參數(shù)的設(shè)置方法。最后,研究了控制系統(tǒng)中實時任務(wù)
    發(fā)表于 08-06 08:35 ?10次下載

    基于頁的8051多任務(wù)模型

      隨著8051微控制器性能的不斷提高,使用多任務(wù)操作系統(tǒng)對單片機(jī)進(jìn)行資源管理已成為當(dāng)代開發(fā)的需要。由于受靜態(tài)鏈接的限制,8051系統(tǒng)的多任務(wù)開發(fā)需要處理代碼重入(reentran
    發(fā)表于 09-25 17:34 ?936次閱讀
    基于頁的8051多<b class='flag-5'>任務(wù)模型</b>

    基于改進(jìn)蜂群算法的多維QoS云計算任務(wù)調(diào)度算法

    針對云計算環(huán)境下用戶日益多樣化的QoS需求和高效的資源調(diào)度要求,提出了基于改進(jìn)蜂群算法的多維QoS云計算任務(wù)調(diào)度算法,其中包括構(gòu)建任務(wù)模型、云資源模型和用戶QoS模型。為了獲得高效的調(diào)
    發(fā)表于 12-01 16:11 ?0次下載

    嵌入式多核處理器任務(wù)調(diào)度研究

    任務(wù)模型而選擇粒子群算法的適應(yīng)度函數(shù),綜合利用局部最優(yōu)極值和全局最優(yōu)極值的優(yōu)勢,優(yōu)化了粒子群算法中存在的過早收斂問題,使算法具有較高的收斂效率。實驗結(jié)果表明,與基于遺傳算法的多核多線程任務(wù)調(diào)度算法相比,該算法
    發(fā)表于 01-17 17:49 ?1次下載
    嵌入式多核處理器<b class='flag-5'>任務(wù)</b>調(diào)度研究

    一種基于神經(jīng)網(wǎng)絡(luò)的聯(lián)合識別方法

    從事件時序關(guān)系與因果關(guān)系的關(guān)聯(lián)性出發(fā),提出基于神經(jīng)網(wǎng)絡(luò)的聯(lián)合識別方法。將時序關(guān)系和因果關(guān)系識別分別作為主任務(wù)和輔助任務(wù),設(shè)計共享輔助任務(wù)中編碼層、解碼層和編解碼層的3種聯(lián)合識別模型,通
    發(fā)表于 03-25 15:47 ?11次下載
    一種基于神經(jīng)網(wǎng)絡(luò)的聯(lián)合識別方法

    開源軟件-Sogou C++ Workflow高性能C++服務(wù)器引擎

    ./oschina_soft/gitee-workflow.zip
    發(fā)表于 06-20 09:36 ?1次下載
    開源軟件-Sogou C++ <b class='flag-5'>Workflow</b>高性能C++服務(wù)器引擎

    模型任務(wù)的評價指標(biāo)體系

    1. 寫在前面 模型“好”與“壞”的評價指標(biāo)直接由業(yè)務(wù)目標(biāo)/任務(wù)需求決定。我們需要做的是:根據(jù)具體的業(yè)務(wù)目標(biāo)/任務(wù)需求去選擇相應(yīng)的評價指標(biāo),繼而選出符合業(yè)務(wù)目標(biāo)/任務(wù)需求的好
    的頭像 發(fā)表于 01-11 10:10 ?752次閱讀

    基于M55H的定制化backbone模型AxeraSpine

    Backbone模型是各種視覺任務(wù)訓(xùn)練的基石,視覺任務(wù)模型的性能和模型的速度都受backbone模型的影響
    的頭像 發(fā)表于 10-10 16:09 ?785次閱讀
    基于M55H的定制化backbone<b class='flag-5'>模型</b>AxeraSpine

    workflow異步任務(wù)調(diào)度編程范式

    ,workflow是一個異步任務(wù)調(diào)度編程范式,封裝了6種異步資源:CPU計算、GPU計算、網(wǎng)絡(luò)、磁盤I/O、定時器、計數(shù)器,以回調(diào)函數(shù)模式提供給用戶使用,概括起來實際上主要是兩個功能:1、屏蔽阻塞調(diào)用的影響,使阻塞調(diào)用的開發(fā)接口變?yōu)楫惒降?,充分利用計算資
    的頭像 發(fā)表于 11-09 09:42 ?386次閱讀
    <b class='flag-5'>workflow</b>異步<b class='flag-5'>任務(wù)</b>調(diào)度編程范式