`
wbj0110
  • 浏览: 1610267 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

epoll

阅读更多
首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作的内核对象。
 
    不管是文件,还是套接字,还是管道,我们都可以把他们看作流。
 
    之后我们来讨论I/O的操作,通过read,我们可以从流中读入数据;通过write,我们可以往流写入数据。现在假定一个情形,我们需要从流中读数据,但是流中还没有数据,(典型的例子为,客户端要从socket读如数据,但是服务器还没有把数据传回来),这时候该怎么办?
 
阻塞:阻塞是个什么概念呢?比如某个时候你在等快递,但是你不知道快递什么时候过来,而且你没有别的事可以干(或者说接下来的事要等快递来了才能做);那么你可以去睡觉了,因为你知道快递把货送来时一定会给你打个电话(假定一定能叫醒你)。
 
非阻塞忙轮询:接着上面等快递的例子,如果用忙轮询的方法,那么你需要知道快递员的手机号,然后每分钟给他挂个电话:“你到了没?”
 
    很明显一般人不会用第二种做法,不仅显很无脑,浪费话费不说,还占用了快递员大量的时间。
    大部分程序也不会用第二种做法,因为第一种方法经济而简单,经济是指消耗很少的CPU时间,如果线程睡眠了,就掉出了系统的调度队列,暂时不会去瓜分CPU宝贵的时间片了。
 
    为了了解阻塞是如何进行的,我们来讨论缓冲区,以及内核缓冲区,最终把I/O事件解释清楚。缓冲区的引入是为了减少频繁I/O操作而引起频繁的系统调用(你知道它很慢的),当你操作一个流时,更多的是以缓冲区为单位进行操作,这是相对于用户空间而言。对于内核来说,也需要缓冲区。
 
假设有一个管道,进程A为管道的写入方,B为管道的读出方。
 
假设一开始内核缓冲区是空的,B作为读出方,被阻塞着。然后首先A往管道写入,这时候内核缓冲区由空的状态变到非空状态,内核就会产生一个事件告诉B该醒来了,这个事件姑且称之为“缓冲区非空”。
    但是“缓冲区非空”事件通知B后,B却还没有读出数据;且内核许诺了不能把写入管道中的数据丢掉这个时候,A写入的数据会滞留在内核缓冲区中,如果内核也缓冲区满了,B仍未开始读数据,最终内核缓冲区会被填满,这个时候会产生一个I/O事件,告诉进程A,你该等等(阻塞)了,我们把这个事件定义为“缓冲区满”。
 
假设后来B终于开始读数据了,于是内核的缓冲区空了出来,这时候内核会告诉A,内核缓冲区有空位了,你可以从长眠中醒来了,继续写数据了,我们把这个事件叫做“缓冲区非满”
    也许事件Y1已经通知了A,但是A也没有数据写入了,而B继续读出数据,知道内核缓冲区空了。这个时候内核就告诉B,你需要阻塞了!,我们把这个时间定为“缓冲区空”。
 
这四个情形涵盖了四个I/O事件,缓冲区满,缓冲区空,缓冲区非空,缓冲区非满(注都是说的内核缓冲区,且这四个术语都是我生造的,仅为解释其原理而造)。这四个I/O事件是进行阻塞同步的根本。(如果不能理解“同步”是什么概念,请学习操作系统的锁,信号量,条件变量等任务同步方面的相关知识)。
 
    然后我们来说说阻塞I/O的缺点。但是阻塞I/O模式下,一个线程只能处理一个流的I/O事件。如果想要同时处理多个流,要么多进程(fork),要么多线程(pthread_create),很不幸这两种方法效率都不高。
    于是再来考虑非阻塞忙轮询的I/O方式,我们发现我们可以同时处理多个流了(把一个流从阻塞模式切换到非阻塞模式再此不予讨论):
while true {
for i in stream[]; {
if i has data
read until unavailable
}
}
    我们只要不停的把所有流从头到尾问一遍,又从头开始。这样就可以处理多个流了,但这样的做法显然不好,因为如果所有的流都没有数据,那么只会白白浪费CPU。这里要补充一点,阻塞模式下,内核对于I/O事件的处理是阻塞或者唤醒,而非阻塞模式下则把I/O事件交给其他对象(后文介绍的select以及epoll)处理甚至直接忽略。
 
    为了避免CPU空转,可以引进了一个代理(一开始有一位叫做select的代理,后来又有一位叫做poll的代理,不过两者的本质是一样的)。这个代理比较厉害,可以同时观察许多流的I/O事件,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流(于是我们可以把“忙”字去掉了)。代码长这样:
while true {
select(streams[])
for i in streams[] {
if i has data
read until unavailable
}
}
    于是,如果没有I/O事件产生,我们的程序就会阻塞在select处。但是依然有个问题,我们从select那里仅仅知道了,有I/O事件发生了,但却并不知道是那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。
    但是使用select,我们有O(n)的无差别轮询复杂度,同时处理的流越多,没一次无差别轮询时间就越长。再次
说了这么多,终于能好好解释epoll了
    epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
    在讨论epoll的实现细节之前,先把epoll的相关操作列出:
 
epoll_create 创建一个epoll对象,一般epollfd = epoll_create()
 
epoll_ctl (epoll_add/epoll_del的合体),往epoll对象中增加/删除某一个流的某一个事件
比如
epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);//注册缓冲区非空事件,即有数据流入
epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);//注册缓冲区非满事件,即流可以被写入
epoll_wait(epollfd,...)等待直到注册的事件发生
(注:当对一个非阻塞流的读写发生缓冲区满或缓冲区空,write/read会返回-1,并设置errno=EAGAIN。而epoll只关心缓冲区非满和缓冲区非空事件)。
 
一个epoll模式的代码大概的样子是:
while true {
active_stream[] = epoll_wait(epollfd)
for i in active_stream[] {
read or write till
}
}
分享到:
评论

相关推荐

    epoll 使用golang实现

    在IT领域,`epoll`是一种高效的I/O事件通知机制,尤其在处理大量并发连接时,它是Linux系统下的首选方案。`epoll`利用内核与用户空间的共享数据结构来减少上下文切换,提高了系统在高并发环境下的性能。本篇文章将...

    linux epoll多线程编程 例子

    在Linux系统中,epoll是I/O多路复用技术的一种高效实现,它极大地改进了传统的轮询方式,尤其在处理大量并发连接时表现出色。本文将深入探讨如何在多线程环境中使用epoll进行程序设计,以提高系统的并行处理能力。 ...

    Linux C++ epoll使用范例

    在Linux系统中,`epoll`是用于I/O多路复用的一种高效机制,尤其适合高并发、大连接数的网络编程场景。本资源提供的"Linux C++ epoll使用范例"包含了客户端、服务端以及一个测试程序,旨在帮助开发者更好地理解和运用...

    epoll函数实现多客户端并发

    1. **创建epoll实例**:通过调用`epoll_create()`函数创建一个`epoll`实例,返回一个表示`epoll`句柄的文件描述符。 2. **注册事件**:使用`epoll_ctl()`函数向`epoll`实例中添加或修改文件描述符的事件类型,如`...

    Linux下使用EPoll+队列+多线程的C++实现

    `epoll`是Linux内核提供的一种I/O多路复用技术,它极大地提高了处理大量并发连接的效率。`epoll`的主要优点在于它能显著降低系统调用的开销,因为它通过水平触发和边缘触发两种模式,使得程序只需关注有事件发生的...

    netty-transport-classes-epoll-4.1.74.Final-API文档-中文版.zip

    赠送jar包:netty-transport-classes-epoll-4.1.74.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.74.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.74.Final-sources.jar;...

    FIFO配合管道PIPE,实现FIFO传递数据,PIPE触发epoll,异步IO效果

    epoll通过注册感兴趣的文件描述符(如FIFO和PIPE的描述符),并设置合适的事件类型(如EPOLLIN表示可读,EPOLLOUT表示可写),可以在数据准备好时,而非在数据等待时,唤醒等待的进程。这种方式大大提高了系统的并发...

    epoll demo(LT和ET)

    **epoll**是Linux内核提供的一种高效I/O事件通知机制,它替代了传统的`poll`和`select`,在高并发I/O处理场景中表现出色。本篇将深入讲解`epoll`的工作原理,以及如何实现`Level Triggered (LT)`模式和`Edge ...

    netty-transport-classes-epoll-4.1.73.Final-API文档-中英对照版.zip

    赠送jar包:netty-transport-classes-epoll-4.1.73.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar;...

    Linux QT Epoll 服务器Demo

    Epoll的核心概念是边缘触发(Edge Triggered)和水平触发(Level Triggered),以及它的核心接口`epoll_create()`、`epoll_ctl()`和`epoll_wait()`。边缘触发意味着只有当文件描述符的状态发生改变时,Epoll才会返回,而...

    netty-transport-classes-epoll-4.1.73.Final-API文档-中文版.zip

    赠送jar包:netty-transport-classes-epoll-4.1.73.Final.jar; 赠送原API文档:netty-transport-classes-epoll-4.1.73.Final-javadoc.jar; 赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar;...

    epoll_udp服务器

    【epoll_udp服务器】是一种在Linux操作系统环境下,利用epoll机制构建的UDP(User Datagram Protocol)服务器,旨在高效地处理大量的并发连接并实现同时收发数据。UDP是一种无连接、不可靠的传输协议,适用于对实时...

    linux epoll的封装类

    在Linux系统中,epoll是I/O多路复用技术的一种高效实现,它提供了一种在高并发场景下处理大量文件描述符(file descriptors)的能力。这个“linux epoll的封装类”是为了简化epoll接口的使用,使得初学者能够更轻松...

    epoll完整源代码实例。

    `epoll`是Linux内核提供的一种高效I/O事件通知机制,主要用于解决多路复用I/O中的性能问题。在传统的`select`、`poll`等I/O模型中,随着监听文件描述符(FD)数量的增长,性能会显著下降。而`epoll`通过引入“边缘...

    epoll服务器、客户端模型

    在IT行业中,网络编程是构建高性能服务的基础,而epoll是Linux系统中用于高并发I/O操作的关键技术。本文将详细解析"epoll服务器、客户端模型",并围绕"epoll"、"服务器"、"客户端"、"网络"和"逻辑"这五个核心标签...

    poll 与epoll分析

    - `epoll_create`:创建一个epoll实例,并返回一个epoll专用的文件描述符。 - `epoll_ctl`:将文件描述符添加到epoll实例中,并指定对每个文件描述符感兴趣的事件。 epoll使用了红黑树来管理所有注册的文件描述符,...

    epoll模型的一个例子

    在Linux系统编程中,`epoll`是一种高效、可扩展的I/O多路复用技术,主要用于处理大量的并发连接。`epoll`模型是解决高并发服务器性能瓶颈的有效手段之一,它比传统的`select`和`poll`模型更加先进,能够更有效地管理...

    linux网络编程之 epoll简介

    ### Linux网络编程之 epoll简介 #### 一、引言 在网络服务器编程中,当面对大量客户端连接时,传统的多线程或select模型已不再适用。本文将深入探讨一种高效的I/O事件处理机制——epoll,并简要介绍另一种高级I/O...

    自己封装的epoll事件驱动模型

    **epoll介绍** `epoll`是Linux内核提供的一种高效、高性能的I/O事件通知机制,主要用于解决多路复用技术(如select、poll)在高并发场景下的性能问题。epoll相比于传统的I/O多路复用技术,具有更好的扩展性和效率,...

    epoll回射服务器

    **epoll回射服务器**是基于C++实现的一种高效网络编程模型,主要应用于多路复用技术中的IO处理。在Linux系统中,epoll是一种I/O事件的通知机制,相较于传统的select和poll,它提供了更高的性能和更灵活的扩展性。本...

Global site tag (gtag.js) - Google Analytics