`
lancelotwjq
  • 浏览: 54918 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

epoll与event_pool

 
阅读更多

  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内核代码学习

    本文将深入解析epoll的内核实现,探讨其核心数据结构、关键操作以及与select的对比。 ### 第一部分:系统调用与内部实现函数 1. `epoll_create`:调用`sys_epoll_create`,创建一个epoll实例,返回一个epoll文件...

    mtcp 数据结构详解

    - `mem_pool_t flow_pool`:用于存储TCP流的内存池。 - `mem_pool_t rv_pool`:用于接收缓冲区的内存池。 - `mem_pool_t sv_pool`:用于发送缓冲区的内存池。 - `mem_pool_t mv_pool`:用于管理其他小对象的内存...

    Go-基于epoll协程池的golang网络库

    Epoll是Event Poll的缩写,它改进了传统的select和poll函数,提供了一种面向多路复用I/O的解决方案。Epoll的核心思想是使用“红黑树”数据结构来存储待监控的文件描述符,并通过水平触发或边缘触发两种模式来提高...

    精选_基于C++11的轻量级网络框架-实现大并发网络IO_源码打包

    2. **I/O多路复用**:通过Epoll的`epoll_wait`函数监控多个文件描述符,当有事件发生时,只唤醒处理线程,提高系统资源利用率。 3. **事件分派**:事件循环接收到事件后,根据事件类型和关联的处理器,将事件分派给...

    nginx源码分析--带注释

    Nginx使用自己的内存池(`ngx_pool_t`)来优化内存分配和释放,以减少系统调用和提高性能。源码中的`alloc`模块提供了关于内存池如何工作的详细信息。 Nginx的事件处理机制也是重点。`ngx_event_t`结构体定义了一个...

    nginx源码分析文档

    4. **事件(Event)模型**:Nginx的核心特性之一是其高效的事件驱动模型,如Linux下的Epoll和FreeBSD下的KQueue等。 5. **模块(Module)**:Nginx采用模块化设计,允许扩展功能。这些模块包括核心模块、HTTP模块...

    nginx 源代码 注释版

    3. **网络连接处理**:`src/event/ngx_event_connections.c`和`src/event/ngx_event_pipe.c`处理客户端与服务器之间的连接和数据传输。Nginx会根据不同的操作系统选择合适的网络API进行优化。 4. **HTTP模块**:...

    reading-code-of-nginx-1.9.2_y123456yz.tar.gz

    `ngx_pool_t`结构体定义了内存池的数据结构。 7. **配置解析**:Nginx的配置文件解析由`ngx_conf_file`模块完成,`ngx_conf_parse`函数逐行读取配置并解析。 三、源码注释与学习方法 该压缩包包含详尽的函数中文...

    nginx开源代码

    Nginx使用自定义的内存池`ngx_pool_t`来管理内存分配,减少内存碎片,提高内存利用率。内存池在多个请求之间共享,减少了大量的内存分配和释放操作。 5. **HTTP模块**: HTTP模块是Nginx的核心部分,负责处理HTTP...

    cpp-nginx192源码通读分析注释

    Nginx使用自定义的内存池`ngx_pool_t`来管理内存,避免频繁的内存分配和释放,提高性能。`ngx_palloc()`和`ngx_pcalloc()`等函数用于在内存池中分配和清理内存。 8. **多进程与信号处理** Nginx支持多进程模型,...

    nginx 源码剖析

    两个重点讲解的文件可能详细解析了`ngx_pool_t`结构体及其相关函数,如`ngx_palloc()`和`ngx_pcalloc()`。 4. **配置解析** Nginx的配置文件解析是通过`ngx_conf_parse()`函数实现的,它将配置文件转化为一系列...

    python中aioysql(异步操作MySQL)的方法

    - IO复用(如select、poll、epoll等):通过检查描述符状态来决定何时进行读写,减少阻塞时间,但检查过程仍可能阻塞。 - 信号驱动IO:描述符准备就绪时,内核发送信号通知,需要处理信号和数据。 - 异步IO:只需...

    Nginx源代码分析.pdf

    - **内存池**:Nginx使用内存池(`ngx_pool_t`)来优化内存分配和释放。内存池允许一次性分配一大块内存,然后从中分配小块内存,减少系统调用的开销。每个内存池由一系列连续的内存块组成,可以高效地管理内存碎片...

    ngnix源码 并携带详细注释说明 新手必备

    源码中会有关于`ngx_pool_t`结构体和相关函数的说明。 10. **多进程与线程模型**:Nginx通常采用主进程+工作进程的模型,主进程负责管理配置和子进程,工作进程处理实际的网络事件。注释会揭示这一模型的细节。 ...

    Nginx-1.7.3:Nginx源码阅读注解

    2. **事件模型**:Nginx采用多事件驱动模型,支持epoll、kqueue、select等不同的事件处理机制。在`src/core/ngx_event.c`中,Nginx会根据操作系统选择合适的事件模型。 3. **网络连接处理**:`ngx_connection_s`...

    libuv-1.37.0.zip

    * 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 ...

    swoole_process实现进程池的方法示例

    2. **Event Loop(事件循环)**:Swoole封装了epoll实现的Reactor线程模型,可以设置read和write事件的监听回调。事件循环负责处理epoll返回的事件,调用相应的回调函数。不过,这不适用于PHP-FPM环境,因为FPM在...

    nginx-1.14.2:nginx1.14.2版本原始代码,供学习使用,随后会添加一些自己理解的注释

    2. **事件模块(Event Modules)**:Nginx的事件模型支持多种操作系统下的异步I/O处理,如epoll、kqueue、poll等。这些事件处理机制位于`src/core/ngx_event.c`和`src/event/*`目录下。 3. **网络连接模块...

Global site tag (gtag.js) - Google Analytics