epoll
is a scalable I/O event notification . 它在内核2.5.44首次引入, 用来取代POSIX select和poll系统调用。
说到select和poll,也就是IO多路转接,在APUE 14.5节有详细介绍:
转自http://blog.csdn.net/delphiwcdj/article/details/8827659
------------------------------------------------
当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中使用阻塞I/O:
但是如果需要从多个描述符读,上面的方法是不行的,如果仍旧使用阻塞I/O,那么就可能长时间阻塞在一个描述符上,而另一个描述符虽有很多数据却不能得到及时处理。针对这个问题,有哪些处理方法呢?
while ( (n = read(STDIN_FILENO, buf,BUFSIZ)) > 0 ) { if( write(STDOUT_FILENO, buf, n) != n ) { printf("write error\n"); return1; } }
方法1:
用fork将一个进程变成两个进程,每个进程处理一条数据通路,即每个进程都执行阻塞read。
问题是:在进程终止时,使程序变得复杂。
方法2:
使用多线程单进程,这避免了终止的复杂性。
问题是:但却要求处理线程之间的同步,依然没有摆脱复杂性。
方法3:
使用单进程非阻塞I/O读数据,即轮询(polling)的方式。将多个描述符都设置为非阻塞的,对第一个描述符发一个read,如果该输入上有数 据,则读数据并处理它;如果无数据可读,则read立即返回。然后对第二个描述符做同样的处理。所有描述符处理完之后,等待若干秒然后再进行轮询。
问题是:浪费CPU时间,因为大多数时间实际是无数据可读的,但仍花费时间不断反复执行read系统调用,在多任务系统中应当避免使用这种方法。
方法4:
异步I/O(asynchronous I/O),其思想是:告知内核启动某个操作,并让内核在整个操作(包括将数据从内核复制到我们自己的缓冲区)完成后通知我们。即,异步I/O模型是由内核通知我们I/O操作合适完成。
问题是:并非所有系统都支持这种机制。
方法5:
使用I/O多路转接(I/Omultiplexing)。先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I /O时,该函数才返回,在返回时,此函数告诉进程哪些描述符已准备好可以进行I/O。poll、pselect和select这三个函数使我们能够执行I /O多路转接。即,我们使用select可以等待多个描述符就绪。
-----------------------------------
在监控文件数量n很大的时候,select和poll的算法复杂度为O(n),而epoll的算法复杂度为O(1)。因而性能会提高很多。
epoll只有三个API[1] :
int epoll_create(int size);
Creates an epoll object and returns its file descriptor.
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
Controls (configures) which file descriptors are watched by this object, and for which events.
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
Waits for any of the registered events, until at least one occurs or the timeout elapses.
Glusterfs使用event_pool封装了epoll。相关代码在libglusterfs/src/event-epoll.c
主要有如下几个函数:
.new = event_pool_new_epoll,
.event_register = event_register_epoll,
.event_select_on = event_select_on_epoll,
.event_unregister = event_unregister_epoll,
.event_dispatch = event_dispatch_epoll
static struct event_pool * event_pool_new_epoll (int count) { struct event_pool *event_pool = NULL; int epfd = -1; //申请空间,event_pool封装了下epoll event_pool = GF_CALLOC (1, sizeof (*event_pool), gf_common_mt_event_pool); event_pool->count = count; event_pool->reg = GF_CALLOC (event_pool->count, sizeof (*event_pool->reg), gf_common_mt_reg); //获得epoll的文件描述符 epfd = epoll_create (count); event_pool->fd = epfd; event_pool->count = count; pthread_mutex_init (&event_pool->mutex, NULL); pthread_cond_init (&event_pool->cond, NULL); out: return event_pool; }
int event_register_epoll (struct event_pool *event_pool, int fd, event_handler_t handler, void *data, int poll_in, int poll_out) { .... //如果满了,就扩容1倍 if (event_pool->count == event_pool->used) { event_pool->count *= 2; event_pool->reg = GF_REALLOC (event_pool->reg, event_pool->count * sizeof (*event_pool->reg)); if (!event_pool->reg) { gf_log ("epoll", GF_LOG_ERROR, "event registry re-allocation failed"); goto unlock; } } idx = event_pool->used; event_pool->used++; //向event_pool中加入一个注册信息 event_pool->reg[idx].fd = fd; event_pool->reg[idx].events = EPOLLPRI; event_pool->reg[idx].handler = handler; event_pool->reg[idx].data = data; .... event_pool->changed = 1; epoll_event.events = event_pool->reg[idx].events; ev_data->fd = fd; ev_data->idx = idx; //注册到epoll ret = epoll_ctl (event_pool->fd, EPOLL_CTL_ADD, fd, &epoll_event); ....
相关推荐
本文将深入解析epoll的内核实现,探讨其核心数据结构、关键操作以及与select的对比。 ### 第一部分:系统调用与内部实现函数 1. `epoll_create`:调用`sys_epoll_create`,创建一个epoll实例,返回一个epoll文件...
- `mem_pool_t flow_pool`:用于存储TCP流的内存池。 - `mem_pool_t rv_pool`:用于接收缓冲区的内存池。 - `mem_pool_t sv_pool`:用于发送缓冲区的内存池。 - `mem_pool_t mv_pool`:用于管理其他小对象的内存...
Epoll是Event Poll的缩写,它改进了传统的select和poll函数,提供了一种面向多路复用I/O的解决方案。Epoll的核心思想是使用“红黑树”数据结构来存储待监控的文件描述符,并通过水平触发或边缘触发两种模式来提高...
2. **I/O多路复用**:通过Epoll的`epoll_wait`函数监控多个文件描述符,当有事件发生时,只唤醒处理线程,提高系统资源利用率。 3. **事件分派**:事件循环接收到事件后,根据事件类型和关联的处理器,将事件分派给...
Nginx使用自己的内存池(`ngx_pool_t`)来优化内存分配和释放,以减少系统调用和提高性能。源码中的`alloc`模块提供了关于内存池如何工作的详细信息。 Nginx的事件处理机制也是重点。`ngx_event_t`结构体定义了一个...
4. **事件(Event)模型**:Nginx的核心特性之一是其高效的事件驱动模型,如Linux下的Epoll和FreeBSD下的KQueue等。 5. **模块(Module)**:Nginx采用模块化设计,允许扩展功能。这些模块包括核心模块、HTTP模块...
3. **网络连接处理**:`src/event/ngx_event_connections.c`和`src/event/ngx_event_pipe.c`处理客户端与服务器之间的连接和数据传输。Nginx会根据不同的操作系统选择合适的网络API进行优化。 4. **HTTP模块**:...
`ngx_pool_t`结构体定义了内存池的数据结构。 7. **配置解析**:Nginx的配置文件解析由`ngx_conf_file`模块完成,`ngx_conf_parse`函数逐行读取配置并解析。 三、源码注释与学习方法 该压缩包包含详尽的函数中文...
Nginx使用自定义的内存池`ngx_pool_t`来管理内存分配,减少内存碎片,提高内存利用率。内存池在多个请求之间共享,减少了大量的内存分配和释放操作。 5. **HTTP模块**: HTTP模块是Nginx的核心部分,负责处理HTTP...
Nginx使用自定义的内存池`ngx_pool_t`来管理内存,避免频繁的内存分配和释放,提高性能。`ngx_palloc()`和`ngx_pcalloc()`等函数用于在内存池中分配和清理内存。 8. **多进程与信号处理** Nginx支持多进程模型,...
两个重点讲解的文件可能详细解析了`ngx_pool_t`结构体及其相关函数,如`ngx_palloc()`和`ngx_pcalloc()`。 4. **配置解析** Nginx的配置文件解析是通过`ngx_conf_parse()`函数实现的,它将配置文件转化为一系列...
- IO复用(如select、poll、epoll等):通过检查描述符状态来决定何时进行读写,减少阻塞时间,但检查过程仍可能阻塞。 - 信号驱动IO:描述符准备就绪时,内核发送信号通知,需要处理信号和数据。 - 异步IO:只需...
- **内存池**:Nginx使用内存池(`ngx_pool_t`)来优化内存分配和释放。内存池允许一次性分配一大块内存,然后从中分配小块内存,减少系统调用的开销。每个内存池由一系列连续的内存块组成,可以高效地管理内存碎片...
源码中会有关于`ngx_pool_t`结构体和相关函数的说明。 10. **多进程与线程模型**:Nginx通常采用主进程+工作进程的模型,主进程负责管理配置和子进程,工作进程处理实际的网络事件。注释会揭示这一模型的细节。 ...
2. **事件模型**:Nginx采用多事件驱动模型,支持epoll、kqueue、select等不同的事件处理机制。在`src/core/ngx_event.c`中,Nginx会根据操作系统选择合适的事件模型。 3. **网络连接处理**:`ngx_connection_s`...
* Full-featured event loop backed by epoll, kqueue, IOCP, event ports. * Asynchronous TCP and UDP sockets * Asynchronous DNS resolution * Asynchronous file and file system operations * File ...
2. **Event Loop(事件循环)**:Swoole封装了epoll实现的Reactor线程模型,可以设置read和write事件的监听回调。事件循环负责处理epoll返回的事件,调用相应的回调函数。不过,这不适用于PHP-FPM环境,因为FPM在...
2. **事件模块(Event Modules)**:Nginx的事件模型支持多种操作系统下的异步I/O处理,如epoll、kqueue、poll等。这些事件处理机制位于`src/core/ngx_event.c`和`src/event/*`目录下。 3. **网络连接模块...