libev教程一:libev簡單入門
阿新 • • 發佈:2019-01-25
首先我們關注一下reactor本身。在libev下面reactor物件稱為event_loop.
event_loop允許動態建立和銷燬,並且允許繫結自定義資料
struct ev_loop * ev_loop_new (unsignedint flags);
void ev_loop_destroy (EV_P);
void ev_set_userdata (EV_P_ void*data);
void*ev_userdata (EV_P);
我們這裡主要關注一下flags.這裡面主要是選擇使用什麼backend來進行poll操作,可以選擇的有:
- EVBACKEND_SELECT
- EVBACKEND_POLL
- EVBACKEND_EPOLL // 通常我們選擇這個
- EVBACKEND_KQUEUE
- EVBACKEND_DEVPOLL
- EVBACKEND_PORT
但是還有三個比較重要選項:
- EVFLAG_NOINOTIFY // 不適用inofity呼叫來使用ev_stat.這樣可以減少fd使用。
- EVFLAG_SIGNALFD // 使用signalfd來檢測訊號是否發生,同樣這樣可以減少fd使用。
大部分時候我們使用EVFLAG_AUTO(0)一般就足夠滿足需求了,從程式碼角度來看如果支援epoll的話那麼首先會選擇epoll. 因為在watcher的回撥函式裡面是可以知道當前event_loop的,這樣就可以獲得自定義資料。然後我們看看這個event_loop如何執行和停止的
void ev_run (EV_P_ int flags);
void ev_break (EV_P_ int how);
同樣我們這裡比較關注flags和how這兩個引數。flags有下面這幾個:
- 0.通常這是我們想要的,每次輪詢在poll都會等待一段時間然後處理pending事件。
- EVRUN_NOWAIT.執行一次,在poll時候不會等待。這樣效果相當於只是處理pending事件。
- EVRUN_ONCE.執行一次,但是在poll時候會等待,然後處理pending事件。
而how有下面這幾個:
- EVBREAK_ONE.只是退出一次ev_run這個呼叫。通常來說使用這個就可以了。
- EVBREAK_ALL.退出所有的ev_run呼叫。這種情況存在於ev_run在pengding處理時候會遞迴呼叫。
在backend/epoll底層每次epoll_wait時候,libev提供了介面回撥可以在epoll_wait前後呼叫
void ev_set_loop_release_cb (loop,void(*release)(EV_P),void(*acquire)(EV_P))
staticvoid
epoll_poll (EV_P_ ev_tstamp timeout)
{
/* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */
/* the default libev max wait time, however. */
EV_RELEASE_CB;
eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax,
epoll_epermcnt ?0: ev_timeout_to_ms (timeout));
EV_ACQUIRE_CB;
}
在event_loop裡面我們還關心一件事情,就是每次event_loop輪詢的時間長短。通常來說這個不會是太大問題,但是在高效能情況下面我們需要設定
void ev_set_io_collect_interval (EV_P_ ev_tstamp interval);
void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval);
在ev_run裡面有使用這些引數的程式碼比較麻煩。但是大意是這樣,如果我們這是了timeout_interval的話,那麼我們每次檢查timeout時間的話必須在timeout_interval,使用這段時間ev_sleep.但是這個又會影響到io_interval,所以內部做了一些換算,換算的結果作為epoll_wait超時時間。不過同樣在大部分時候我們不需要關心它,預設時候是0.0,系統會使用最快的響應方式來處理。