• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰(shuí)的技術(shù)博客

            感興趣領(lǐng)域:高性能服務(wù)器編程,存儲(chǔ),算法,Linux內(nèi)核
            隨筆 - 210, 文章 - 0, 評(píng)論 - 1183, 引用 - 0
            數(shù)據(jù)加載中……

            libevent事件處理框架分析

            這兩天大致看了看libevent的代碼,簡(jiǎn)單做一個(gè)分析.

            libevent最大的特點(diǎn)就是封裝了對(duì)以下三種事件的響應(yīng):IO事件,定時(shí)器事件,信號(hào)事件.這里就分析libevent如果做到這一點(diǎn)的,在libevent中還包括一些其他的功能(如緩沖區(qū)),但是我這里就重點(diǎn)講解這一部分了.

            事件原型,簡(jiǎn)單看一看用于封裝事件的結(jié)構(gòu)體定義:
            struct event {
                TAILQ_ENTRY (
            event) ev_next;
                TAILQ_ENTRY (
            event) ev_active_next;
                TAILQ_ENTRY (
            event) ev_signal_next;
                unsigned 
            int min_heap_idx;    /* for managing timeouts */

                
            struct event_base *ev_base;

                
            int ev_fd;
                
            short ev_events;
                
            short ev_ncalls;
                
            short *ev_pncalls;    /* Allows deletes in callback */

                
            struct timeval ev_timeout;

                
            int ev_pri;        /* smaller numbers are higher priority */

                
            void (*ev_callback)(intshortvoid *arg);
                
            void *ev_arg;

                
            int ev_res;        /* result passed to event callback */
                
            int ev_flags;
            };
            其中的ev_callback就是回調(diào)函數(shù),也就是說當(dāng)所關(guān)注的事件發(fā)生時(shí)所要觸發(fā)的函數(shù)是注冊(cè)到這個(gè)函數(shù)指針中的.

            1)IO事件:再簡(jiǎn)單不過了,對(duì)select/epoll/poll等之類的調(diào)用進(jìn)行封裝即可,所提供的接口無(wú)非這幾種:
            struct eventop {
                
            const char *name;
                
            void *(*init)(struct event_base *);
                
            int (*add)(void *struct event *);
                
            int (*del)(void *struct event *);
                
            int (*dispatch)(struct event_base *void *struct timeval *);
                
            void (*dealloc)(struct event_base *void *);
                
            /* set if we need to reinitialize the event base */
                
            int need_reinit;
            };
            在我看過的很多開源服務(wù)器源碼(如lighttpd)中都有類似的封裝,不是什么新鮮的東西.

            2)定時(shí)器事件:libevent采用堆數(shù)據(jù)結(jié)構(gòu)存放所要定時(shí)的事件的時(shí)間,大家知道堆可以用來(lái)實(shí)現(xiàn)優(yōu)先隊(duì)列,在這里,所有的定時(shí)器就放在這樣的一個(gè)數(shù)據(jù)結(jié)構(gòu)中了.

            3)信號(hào)事件:所有的信號(hào)都注冊(cè)回調(diào)函數(shù)為evsignal_handler(在signal.c中),這個(gè)函數(shù)的功能就是在某信號(hào)被觸發(fā)的時(shí)候?qū)⒃撔盘?hào)被觸發(fā)的計(jì)數(shù)器加1,同時(shí)置一個(gè)標(biāo)志位表示有信號(hào)被觸發(fā).

            現(xiàn)在,把所有這些結(jié)合起來(lái),看看libevent框架的主循環(huán)是如何工作的,用簡(jiǎn)單的偽碼表示:
            主循環(huán)
                  更新當(dāng)前時(shí)間

                  將當(dāng)前時(shí)間與存放時(shí)間的堆中的時(shí)間依次進(jìn)行比較,由于是采用堆實(shí)現(xiàn)的,這里查找相當(dāng)?shù)目?于是所有可以被觸發(fā)的定時(shí)器事件都從堆中被取出,同時(shí)取下的事件被放到一個(gè)活動(dòng)事件的隊(duì)列中

                  調(diào)用封裝IO操作的dispatch函數(shù),在其中也將被觸發(fā)的IO事件加入到那個(gè)存放活動(dòng)事件的隊(duì)列中

                  在dispatch的函數(shù)中如果信號(hào)被觸發(fā)的標(biāo)志位被置位,說明有信號(hào)被觸發(fā),調(diào)用evsignal_process函數(shù),這個(gè)函數(shù)的功能也是把所有被觸發(fā)的事件放到活動(dòng)事件的隊(duì)列中

                   好了,現(xiàn)在所有可以被觸發(fā)的事件都在活動(dòng)事件隊(duì)列中了,依次遍歷取出來(lái)調(diào)用它們注冊(cè)的回調(diào)函數(shù)就成了.



            上面就是libevent處理這三種事件的大體框架.

            說一說我認(rèn)為這個(gè)框架存在的缺點(diǎn):
            1) callback函數(shù)只能有一個(gè),假設(shè)這樣一個(gè)場(chǎng)景,我需要對(duì)某個(gè)連接socket同時(shí)監(jiān)控它的可讀/可寫/超時(shí)事件,那么我需要針對(duì)同一個(gè)socket fd生成三個(gè)event對(duì)象.

            2) 在主循環(huán)中,每次都要去查詢存放時(shí)間的堆看看有沒有定時(shí)器事件可以被觸發(fā),問題在于,很多時(shí)候,一個(gè)主循環(huán)很快就到了下一次,而時(shí)間過去的并不多,這次去檢查時(shí)間是冗余的操作,當(dāng)然了,由于libevent的定時(shí)器是精確到毫秒級(jí)別的,所以有這么做的必要,但是在一個(gè)真正的服務(wù)器中,我懷疑有多少需要精確到微秒級(jí)別的事件,所以呢,我覺得這個(gè)可以做一個(gè)改進(jìn),每次更新時(shí)間之后跟上一次更新的時(shí)間做一個(gè)比較,如果超過了一秒(或者把這個(gè)間隔改成可以由使用者配置的)再去檢查堆上面的時(shí)間.





            posted on 2009-01-03 00:14 那誰(shuí) 閱讀(45256) 評(píng)論(8)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)編程服務(wù)器設(shè)計(jì)libevent

            評(píng)論

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            libevent的源代碼我也看過,不過你說的這兩個(gè)都不是問題:
            1) 所關(guān)心的不同事件類型可以在注冊(cè)時(shí)指明,不必通過不同的event對(duì)象來(lái)設(shè)置。如:
            event_set(&evfifo, socket, EV_READ | EV_WRITE, fifo_read, &evfifo);
            而當(dāng)所關(guān)心的事件觸發(fā)的時(shí)候,libevent在調(diào)用你的回調(diào)函數(shù)的時(shí)候會(huì)指明事件的類型——通過回調(diào)函數(shù)的第二個(gè)參數(shù)(是一個(gè)|值)。你只要在回調(diào)函數(shù)判斷一下事件類型即可。
            2) libevent不會(huì)做多余的檢查。主循環(huán)的timeout_next會(huì)取出距離下一個(gè)超時(shí)時(shí)間有多久(最小堆的取最小值操作,是O(1)的復(fù)雜度),而這個(gè)timeout最終會(huì)交給類似于select/poll/epoll_wait這樣的系統(tǒng)調(diào)用,作為timeout。也就說,在這個(gè)timeout時(shí)間內(nèi),如果沒有在select/epoll上注冊(cè)的事件發(fā)生,libevent是阻塞了的。libevent的這種處理方式已經(jīng)是慣例了的。你那種“改進(jìn)”不精確,也不高效。
            以上如有謬誤,歡迎互相交流指出 :-)
            2009-01-04 09:53 | Joshua Zhu

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            @Joshua Zhu
            受教了,謝謝~~
            2009-01-04 10:05 | 創(chuàng)

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            callbal函數(shù)確實(shí)可以設(shè)定多個(gè)事件。
            第二個(gè)問題還沒看到。學(xué)習(xí)libevent中。
            2009-02-18 16:43 | cocobear

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            @Joshua Zhu
            nginx 呵呵
            我記得你的ppt里邊有nginx關(guān)于超時(shí)的處理哈,就是你說的第二點(diǎn)。
            膜拜
            2010-02-03 23:33 | kairos

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            callback不能立即返回 豈不是hold住了主循環(huán)
            2011-12-07 12:01 | ever

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            定時(shí)器如果是用heap實(shí)現(xiàn)的話應(yīng)該是log(N)把
            2013-03-03 12:21 | leehark

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            @leehark
            是o(1)因?yàn)槎岩呀?jīng)建好,直接Get就行
            2013-07-03 13:12 | hailong

            # re: libevent事件處理框架分析  回復(fù)  更多評(píng)論   

            @hailong
            拿走后,堆的恢復(fù)是logn
            2016-03-04 15:23 | jiao
            久久综合久久综合九色| 开心久久婷婷综合中文字幕| .精品久久久麻豆国产精品| 97久久天天综合色天天综合色hd| 中文字幕成人精品久久不卡| 国产精品VIDEOSSEX久久发布| 精品久久久久成人码免费动漫| 久久久久亚洲AV无码专区首JN| 精品蜜臀久久久久99网站| 久久久91人妻无码精品蜜桃HD| 无码国内精品久久人妻| 99久久国产综合精品五月天喷水 | 热re99久久精品国99热| 99热热久久这里只有精品68| 亚洲精品午夜国产VA久久成人| 国产精品va久久久久久久| 精品久久久久香蕉网| 中文精品久久久久人妻| 国产成人精品久久| AV无码久久久久不卡网站下载 | 国产精品毛片久久久久久久| 久久这里只精品99re66| 国产三级观看久久| 色综合久久中文综合网| 欧美大香线蕉线伊人久久| 国产成人精品综合久久久| 热综合一本伊人久久精品| 精品久久久久久无码免费| 亚洲欧美日韩精品久久| 久久91精品久久91综合| 久久精品国产亚洲AV麻豆网站 | 一级做a爰片久久毛片16| 粉嫩小泬无遮挡久久久久久| 久久人妻少妇嫩草AV无码专区| 久久久精品国产免大香伊| 久久婷婷色综合一区二区| 久久精品国产AV一区二区三区| 色妞色综合久久夜夜| 97精品伊人久久久大香线蕉| 国产成人无码精品久久久性色| 日韩人妻无码一区二区三区久久 |