<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Netplus試圖解決什么問題

          共 4562字,需瀏覽 10分鐘

           ·

          2021-04-18 19:59


          本文為初見,Netplus快速開始之PingPong Example系列第二篇


          1. 背景

          網(wǎng)絡(luò)信息傳遞中的兩個基本問題,即建立連接,傳遞消息,都已被各操作系統(tǒng)解決好了,各家的技術(shù)細(xì)節(jié)并不一樣,暴露出來的接口雖有相似之處,但仍然難以做到一份代碼,到處運(yùn)行。一些代碼庫,如libuv, libevent,在系統(tǒng)兼容以及IO事件通知的上面做得非常優(yōu)秀,然,從實(shí)際應(yīng)用開發(fā)者的角度來看,它們?nèi)匀贿z留了很多需要開發(fā)者自己去解決的問題,如跨平臺的一些細(xì)節(jié)、IO事件處理、線程安全及性能調(diào)優(yōu)、應(yīng)用層協(xié)議的解析。而這些問題都涉及更多的知識以及編程經(jīng)驗(yàn),這就是門檻啊,任何試圖降低門檻的努力都是有價值的,也肯定是值得的。

          為降低門檻,Netplus在很多方面都做嘗試。

          2. Netplus為降低門檻進(jìn)行的嘗試

          2.1 簡化對象管理

          對象管理是個古老的話題,各語言在這方面都做得相當(dāng)出色,尤其是Java,需要的時候,我們new一個,不用的時候,直接置null, 這種簡單直接的使用方式,著實(shí)迷人,c++是否也能如此呢?

          c++在這方面也是努力,stl中有如下方案:

          • std::auto_ptr

          • std::unique_ptr

          • std::shared_ptr

          • std::weak_ptr

          • std::enable_shared_from_this

          已經(jīng)有這么多解決方案了,還沒有解決好問題嗎?為啥,Netplus又造輪子 ?

          簡單列一下理由如下:

          • 并沒有解決好線程安全的問題。

          • shared_ptr使用不當(dāng)會造成二次delete,最典型的當(dāng)屬如這樣的代碼,int* p=new int; std::shared_ptr<int>(p); std::shared_ptr<int>(p)。雖然這是一個錯誤的使用案例,但是我相信寫過這樣代碼的人應(yīng)該不少。

          • 有多種方式獲取到raw_pointer,有了raw_pointer。特別是周期長,不段有新人加入的項(xiàng)目,鬼曉得會有人拿這個raw_pointer來干什么用(最好你不明白我在說什么 )。

          • sizeof(std::shared_ptr<T>) == sizeof(T*)*2,理想的期望當(dāng)然是如sizeof(netp::ref_ptr<T>) == sizeof(T*)

          • std::shared_ptr<T>對象在創(chuàng)建的時候,還會額外new一個對象來存control_block, 這對于有大量小對象的系統(tǒng)來說,性能會受到不少的影響。

          • 工具太多,眼花繚亂,新人會有一些心理負(fù)擔(dān)。

          我說了列一下的,沒想到一直子列了這么多,就點(diǎn)到為止吧。

          注:我列的這些問題,并不是想說std::shared_ptr有多糟糕,除此之外,std::shared_ptr也是有很多好處的,比如,它是非侵入式的,除了托管對象,它還能托管數(shù)組,因可自定義deleter,使得它還可以托管一些其它資源,如file descriptor,等system handle。造成今天這樣的局面,有一些是歷史遺留問題,還有一些就是選擇。

          Netplus其中一個重要的目標(biāo)是降低門檻,因此,易用,夠用,簡潔成為其第一要考慮的問題,綜合考慮之后,Netplus選擇了侵入式的引用計數(shù)方式,它具備如下性質(zhì):

          • 阻止顯式new/delete (編譯器會報錯)

          • sizeof(netp::ref_ptr<T>) == sizeof(T*)

          • 小對象友好

          • 線程安全

          通過這些努力,我們達(dá)成了下面這樣的小目標(biāo)

          • 想要的時候make_ref<T>(...)

          • 不要的時候,直接置null

          詳細(xì)的關(guān)于Netplus智能指針,請參:

          Concept: Smart Pointergithub.com


          2.2 形式上消滅回調(diào)函數(shù)

          先看下面代碼:

          struct foo{};
          struct bar{};
          struct callback_ctx_t {
          foo* foo_ptr;
          bar* bar_ptr;
          };
          typedef void (*callback_t)(int v, callback_ctx_t* ctx);
          void do_async( callback_t cb, callback_ctx_t* ctx ){
          xx_cb = cb;
          xx_ctx = ctx;
          // do ..
          // if the expected event happens in the future, we must call xx_cb(event_result, ctx )
          }
          //this func would be called in future, if event happens
          void do_if_event_ready(){
          int v=8;//set event result value as 8 for simplicity
          xx_cb(v,ctx);
          }

          void callback_impl(int v, callback_ctx_t* ctx) {
          if(v == 8) {
          //do...
          }
          }
          int main(int argc, char** argv) {
          callback_ctx_t* ctx = new callback_ctx_t;
          ctx->foo_ptr = new foo();
          ctx->bar_ptr = new bar();
          do_async(callback_impl, ctx);
          for(;;){}
          }

          這是一個典型的回調(diào)案例。

          do_async調(diào)用后,它的結(jié)果要等到某event發(fā)生之后才會有。于是我們傳入一個函數(shù),這個函數(shù)主要是用來接收將來才會知道的那個值,同時,為了能在回調(diào)函數(shù)里面執(zhí)行相關(guān)的操作,我們可能還要傳入一個ctx,在ctx里面保存需要的上下文。

          回調(diào)雖然能解決問題,但是,它不便于代碼閱讀,不便于直觀的邏輯表達(dá),更不便于資源管理,工程中的很多問題都與回調(diào)有關(guān)。

          我們能否有更好的表達(dá)方式呢?

          我們能不能在do_async返回一個對象,這個對象可以直接取將來的值,值的類型是int?這樣不就沒有回調(diào)了嗎?

          于是,經(jīng)過精心設(shè)計,代碼變成下面這樣:

          netp::ref_ptr<netp::promise<int>> do_async(){
          xx_promise = netp::make_ref<netp::promise<int>>():
          // do ..
          return xx_promise;
          }

          //this func would be called in future, if event happens
          void do_if_event_ready(){
          int v=8;//set event result value as 8 for simplicity
          xx_promsie->set(v);
          }
          struct foo{};
          struct bar{};
          int main(int argc, char** argv) {
          foo* foo_ptr = new foo();
          bar* bar_ptr = new bar();
          netp::ref_ptr<netp::promise<int>> int_p = do_async();
          int_p ->if_done([foo_ptr,bar_ptr](int v){
          //this lambda would be called once the event ready
          if(v == 8) {
          //do ...
          }
          });
          for(;;){}
          }

          有沒有發(fā)現(xiàn)點(diǎn)什么呢?

          我們在形式上消滅了回調(diào),整個代碼的表達(dá),有沒有感覺更直觀一點(diǎn)?請注意if_done這一行,有發(fā)現(xiàn)什么了嗎,仔細(xì)體會,帶著如下問題仔細(xì)體會?

          • 線程調(diào)度的本質(zhì)

          • 協(xié)程的本質(zhì)

          • 任務(wù)調(diào)度的本質(zhì)

          • 任務(wù)與線程,與CPU資源是何關(guān)系,如何最大化cpu利用率?


          Promise的一小步,表達(dá)上的一大步。

          結(jié)合c++11的lambda,終于,異步的代碼看起來,也如同步代碼那般直觀,ctx的傳遞再也不需要構(gòu)造專門的對象,我們可以直接通過lambda捕獲參數(shù)傳入。

          Netplus里,幾乎所有的IO調(diào)用,都是返回Promise對象,函數(shù)簽名如下:

          netp::ref_ptr<netp::promise<int>> ch_write(netp::ref_ptr<netp::packet> const& outlet);
          netp::ref_ptr<netp::promise<int>> ch_write_to(netp::ref_ptr<netp::packet> const& outlet, address const& to);
          netp::ref_ptr<netp::promise<int>> ch_close();
          netp::ref_ptr<netp::channel_dial_promise<int>> dial(std::string const& host,...);

          更多關(guān)于Promise,請參:

          Concept: Promisegithub.com


          3. 隱藏平臺差異,將IO編程的共性進(jìn)行抽象封裝

          將平臺相關(guān)、IO事件處理、線程相關(guān)、性能相關(guān),這些各APP里面都需要考慮的共性,進(jìn)行抽象、封裝。隱藏平臺的細(xì)節(jié)和差異。

          目前Netplus支持如下平臺:

          • Windows on x86

          • Linux on x86/arm

          • IOS/MAC on x86/arm

          • Android on x86/arm

          開發(fā)者再也不用關(guān)心平臺以及平臺相關(guān)的差異性。

          4. 借鑒Netty,Pipeline化消息處理

          Netplus在設(shè)計的時候,借鑒了很多來自netty的概念,如,channel, channel handler, pipeline, executor, scheduler, 那些熟悉 netty的朋友,就算不熟悉c++,應(yīng)該也能快速上手。

          通過Pipeline管理好Handler以及它的次序,便能如流水線一般對協(xié)議進(jìn)行逐層處理,最終將業(yè)務(wù)需要的消息形態(tài)遞送到業(yè)務(wù)邏輯的代碼處。

          通過此設(shè)計,使得開發(fā)者只需專注于自己的業(yè)務(wù)本身,或通過添加新的Handler,去適配自有協(xié)議,便能進(jìn)行網(wǎng)絡(luò)通迅。

          為了便于快速開發(fā),Netplus對http/https/websocket等協(xié)議提供了直接的支持,當(dāng)然,也歡迎各位朋友為其添加其它的協(xié)議,讓Netplus日漸豐滿,我們的目標(biāo)始終是,開箱即用,統(tǒng)統(tǒng)一把梭

          03e1f3bf2f23e56088eeb9d218cdaf03.webp


          欲窮千里目,更上一層樓,下文,我們將聊聊Netplus里面的一些基本概念。


          瀏覽 57
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费日韩在线三级黄色电影网址 | 五月丁香好婷婷网站入口 | 国产精品日韩欧美一级极品欧美日韩一级精品 | 欧美三级视频在线观看 | 影音先锋久久久久AV综合网成人 |