最近了解了一下 Eventloop 这个概念,所以想写一篇文章整理一下思路。
1、Eventloop 是什么?
我在网上看了一些资料,但都比较复杂,而且大多和 JavaScript 扯上关系,对初学者不友好。
我个人理解的 Eventloop,其实就是在一个大循环里,处理各种各样的事件。只是不同的 Eventloop 机制或者库,在性能和适用场景之间有差别罢了。
一个程序,只要它需要一直工作,就会处于一个持续循环运行的状态,我把这个循环的状态,称为 Eventloop。
举个简单的例子:
intmain() { intchoice; do{ //等待用户输入 choice=getch(); switch(choice){ case'q': break; case'a': add_record(); break; [...] } }while(choice!='q'); exit(EXIT_SUCCESS); }
上面这个程序,在一个 while 循环里,根据不同的键盘输入事件,而执行不同的操作。
这就是一个简单的 Eventloop,只是这个 Eventloop 只处理一种事件:键盘输入,且是阻塞等待,虽然很简陋,但是对于上面这个场景而言,已经够用了。
Eventloop 随处可见:
许多开源软件,只要它们有持续运行 + 事件处理的需求,就会有自己的 Eventloop 实现,例如:
图形库 Qt 里的 QGuiApplication::run();
多媒体库 SDL2 里的 SDL_PollEvent();
网络库 Mongoose 里的 mg_mgr_poll();
本质上都是一种 Eventloop,只是由于需求和应用场景的不一样,各自的实现方法有所差异。
合格的 Eventloop:
一个合格的 Eventloop,需要有哪些特性?
我个人认为:
1、不要阻塞,即不要调用可能会阻塞的系统调用,或总是以 nonblocking 的方式调用系统调用。
2、能异步处理事件。
3、性能尽量高,以满足业务需求为下限。
满足上述三点,这个 Eventloop 在功能上就是够用的。
2、Eventloop 怎么用?
基于 select 的 Eventloop:
这是来自 UNIX 网络编程 16.2 章节的一个例子,其大致代码如下:
str_cli(FILE*fp,intsockfd) { ... //setnonblock val=Fcntl(sockfd,F_GETFL,0); Fcntl(sockfd,F_SETFL,val|O_NONBLOCK); //eventloop for(;;){ ... Select(maxfdp1,&rset,&wset,NULL,NULL); if(FD_ISSET(sockfd,&rset)){ //dosomething } ...//otherevent } }
这个程序会从标准输入中读取一行数据,然后通过 socket 发送给服务端,然后接收服务端的响应,最后将响应也写到标准输出。
最关键的点是先调用 fcntl 将所有的输入输出都设置为 nonblock,然后用 select 监测所有的文件描述符。
基本上所有的开源事件库,本质上和这个程序没差别。
各种开源的 Eventloop 库:
由于 Eventloop 是一个比较通用的需求,在开源软件里,有许多优秀的异步事件库都实现了这个功能。
比较适合嵌入式领域异步事件库有 3 个:
libevent:an event notification library.
名气最大,应用最广泛,历史最悠久的跨平台事件库。
libev:a high performance full-featured event loop written in C.
较 libevent 而言,设计更简练,但是对 Windows 支持不够好,并且和开源社区不怎么接轨。
libuv:a multi-platform support library with a focus on asynchronous I/O.
点击查看大图
开发 node.js 的过程中需要一个跨平台的事件库,目前非常活跃,推荐大家重点学习。
libev 最精简,入门最容易,这里用它来介绍一下事件库的用法:
#include#include //定义两个事件watcher ev_iostdin_watcher; ev_timertimeout_watcher; //iowatcher的回调函数 staticvoid stdin_cb(EV_P_ev_io*w,intrevents) { puts("stdinready"); ev_io_stop(EV_A_w); ev_break(EV_A_EVBREAK_ALL); } //timerwatcher的回调函数 staticvoid timeout_cb(EV_P_ev_timer*w,intrevents) { puts("timeout"); ev_break(EV_A_EVBREAK_ONE); } intmain(void) { //定义eventloop structev_loop*loop=EV_DEFAULT; //初始化iowatcher ev_io_init(&stdin_watcher,stdin_cb,/*STDIN_FILENO*/0,EV_READ); ev_io_start(loop,&stdin_watcher); //初始化timerwatcher ev_timer_init(&timeout_watcher,timeout_cb,2,0.); ev_timer_start(loop,&timeout_watcher); //启动eventloop ev_run(loop,0); return0; }
libev 用 watcher 来检测各种事件,当事件发生时,会调用 watcher 的回调函数。
那么,具体支持哪些事件类型呢?
如果你对 libev 感兴趣,可以根据下面这张图阅读其源码:
审核编辑:汤梓红
-
开源
+关注
关注
3文章
3235浏览量
42364 -
javascript
+关注
关注
0文章
516浏览量
53782
原文标题:不懂就问:什么是Eventloop?
文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论