• <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ù),也就是說(shuō)當(dāng)所關(guān)注的事件發(fā)生時(shí)所要觸發(fā)的函數(shù)是注冊(cè)到這個(gè)函數(shù)指針中的.

            1)IO事件:再簡(jiǎn)單不過(guò)了,對(duì)select/epoll/poll等之類(lèi)的調(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;
            };
            在我看過(guò)的很多開(kāi)源服務(wù)器源碼(如lighttpd)中都有類(lèi)似的封裝,不是什么新鮮的東西.

            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)志位被置位,說(shuō)明有信號(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處理這三種事件的大體框架.

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

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





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

            評(píng)論

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

            libevent的源代碼我也看過(guò),不過(guò)你說(shuō)的這兩個(gè)都不是問(wèn)題:
            1) 所關(guān)心的不同事件類(lèi)型可以在注冊(cè)時(shí)指明,不必通過(guò)不同的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ì)指明事件的類(lèi)型——通過(guò)回調(diào)函數(shù)的第二個(gè)參數(shù)(是一個(gè)|值)。你只要在回調(diào)函數(shù)判斷一下事件類(lèi)型即可。
            2) libevent不會(huì)做多余的檢查。主循環(huán)的timeout_next會(huì)取出距離下一個(gè)超時(shí)時(shí)間有多久(最小堆的取最小值操作,是O(1)的復(fù)雜度),而這個(gè)timeout最終會(huì)交給類(lèi)似于select/poll/epoll_wait這樣的系統(tǒng)調(diào)用,作為timeout。也就說(shuō),在這個(gè)timeout時(shí)間內(nèi),如果沒(mé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è)問(wèn)題還沒(méi)看到。學(xué)習(xí)libevent中。
            2009-02-18 16:43 | cocobear

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

            @Joshua Zhu
            nginx 呵呵
            我記得你的ppt里邊有nginx關(guān)于超時(shí)的處理哈,就是你說(shuō)的第二點(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
            日韩欧美亚洲综合久久影院Ds| 国内精品人妻无码久久久影院| 国产精品久久久久影视不卡| jizzjizz国产精品久久| 久久精品国产亚洲AV高清热 | 性高湖久久久久久久久| 无码人妻久久一区二区三区免费丨| 日韩欧美亚洲综合久久| 少妇久久久久久久久久| 激情综合色综合久久综合| 久久精品青青草原伊人| 9999国产精品欧美久久久久久| 激情久久久久久久久久| 91精品国产高清久久久久久io | 久久精品成人国产午夜| 一级做a爰片久久毛片看看 | 无码国内精品久久人妻麻豆按摩| 97视频久久久| 亚洲国产成人精品无码久久久久久综合| 国产99久久久国产精品小说| 国产精品久久久久久| 国产精品久久久久蜜芽| 狠狠色综合网站久久久久久久| 久久精品国产亚洲av麻豆蜜芽| 国产精品免费久久久久影院| 久久久久久夜精品精品免费啦| 亚洲人成网站999久久久综合| 久久精品国产免费一区| 久久夜色精品国产网站| 久久精品成人欧美大片| 日韩亚洲国产综合久久久| 欧美久久一级内射wwwwww.| 久久久久国产精品嫩草影院| 伊人久久大香线焦综合四虎| 无码AV中文字幕久久专区| 久久无码AV一区二区三区| 欧美色综合久久久久久| 久久午夜无码鲁丝片午夜精品| 国产高潮久久免费观看| 久久91这里精品国产2020| 色播久久人人爽人人爽人人片aV |