@淘宝千石
简介
This library provides fully asynchronous versions of most POSIX functions dealing with I/O. Unlike most asynchronous libraries, this not only includes read and write, but also open, stat, unlink and similar functions, as well as less rarely ones such as mknod, futime or readlink. It also offers wrappers around sendfile (Solaris, Linux, HP-UX and FreeBSD, with emulation on other platforms) and readahead (Linux, with emulation elsewhere>). The goal is to enable you to write fully non-blocking programs.
缘起
相信上面这段话已经将libeio的feature讲的足够清楚:提供全套异步文件操作的接口,让使用者能写出完全非阻塞的程序。阻塞意味着低效,但非阻塞一定要有很好的通知机制才能做到高效。
其实linux下的AIO(异步IO)并不是没有解决方案:在用户态,多线程同步来模拟的异步IO,如Glibc 的AIO;以及在内核态实现异步通知,如linux内核2.6.22之后实现的Kernel Native AIO。但两者都存在让使用者望而祛步的问题。
Glibc的AIO bug太多,而且IO发起者并不是最后的IO终结者(callback是在单独的线程执行的);而kernel Native AIO只支持O_DIRECT方式,无法利用Page cache。
正是由于上述原因,Marc Alexander Lehmann大佬决定自己开发一个AIO库,及libeio。libeio也是在用户态用多线程同步来模拟异步IO,但实现更高效,代码也更可靠,目前虽然是beta版,但已经可以上生产了(node.js底层就是用libev和libeio来驱动的)。还要强调一点:libeio里IO的终结者正是当初IO的发起者(这一点非常重要,因为IO都是由用户的request而发起,而IO完成后返回给用户的response也能在处理request的线程中完成)。
实现
一次异步IO操作可以分为三个阶段:
初始化 --> 提交IO --> 通知worker线程 (主线程);
取request --> 执行IO --> 通知主线程 (worker线程);
取response --> callback --> 结束IO (主线程)。
下面我们通过一张流程图来剖析一下libeio的源码实现。
1. 主线程调用eio_init函数,主要是初始化req_queue,res_queue以及对应的mutex和cond;
2-3. 所有的IO操作其实都是对eio_sumbit的调用,而eio_sumbit的职能是将IO操作封装为request并插入到req_queue;并调用cond_signal向worker线程发出reqwait已经OK的信号;
libeio处理流程图
4. worker线程被创建后执行的函数为etp_proc,etp_proc启动后会一直等待reqwait条件的出现;
5-6. 当reqwait条件变量满足时,etp_proc从req_queue中取得一个待处理的request;并调用eio_execute来同步执行该IO操作;
7-8. eio_execute完成后,将response插入到res_queue队列中;同时调用want_poll来通知主线程request已经处理完毕;
9. 这里worker线程通知主线程的机制是通过向pipe[1]写一个byte数据;
10. 当主线程发现pipe[0]可读时,就调用eio_poll;
11. eio_poll从res_queue里取response,并调用该IO操作在init时设置的callback函数完成后续处理;
12. 在res_queue中没有待处理response时,调用done_poll;
13-14. done_poll从pipe[0]读出一个byte数据,该IO操作完成。
后记
libeio的实现就是这么简洁,这里需要说明两点:
1. 在worker线程完成IO请求,通知主线程的机制是需要使用者自定义的,wait_poll和done_poll就是libeio提供给使用者的接口(pipe是一种常用的线程通知机制)。
2. worker线程并不是为每个请求都创建一个,而是维护了一个worker线程池,关于这部分将会在下面的文章中单独讲到。
参考
《libeio接口文档》
http://pod.tst.eu/http://cvs.schmorp.de/libeio/eio.pod
《linux异步IO浅析》
http://hi.baidu.com/_kouu/blog/item/e225f67b337841f42f73b341.html
《linux AIO (异步IO) 那点事儿》
http://club.cnodejs.org/topic/4f16442ccae1f4aa270010a7
分享到:
相关推荐
libeio是libev的一个扩展,它提供了一个异步I/O接口,允许开发者执行阻塞的I/O操作而不阻塞事件循环。libeio通过在后台线程池中执行这些操作,使得主线程可以继续处理其他事件。 libeio的主要特性包括: 1. **非...
总结,libuv-httpserver源码分析让我们深入了解了如何利用libuv构建高性能的HTTP服务器。通过对事件循环、连接管理和请求处理等核心模块的深入学习,我们可以更好地理解和应用libuv库,从而开发出更高效的网络应用...
通过libeio,开发者可以编写非阻塞的I/O代码,使得程序在等待I/O操作完成时可以执行其他任务,提高系统资源利用率和整体性能。 **libeio的核心特性** 1. **线程池**:libeio使用一个内部线程池来处理异步I/O请求,...
libeio则是一个用于C语言的全功能异步I/O库,提供异步版本的POSIX API,包括读取、写入、打开、关闭、统计等文件操作。 在Node.js中,异步接口的实现主要包括使用uv(libuv)封装的libev事件循环,以及在Windows...
Node.js的核心技术基础库包括libev(事件循环)、libeio(非阻塞POSIX,线程池)以及Google研发的V8 JavaScript引擎。V8引擎是Node.js运行速度快的一个重要原因,因为它的性能接近本地代码。在淘宝中,Node.js的事件...
Linux中可以通过自定义实现或使用库如`libeio`、`glib`的线程池功能。 5. **协程**:协程是一种轻量级的并发形式,比线程更高效,因为它不需要操作系统调度。协程的切换由用户代码控制,可以在任意位置挂起和恢复...