首页 > 其他分享 >epoll模型、边缘触发和条件触发记录

epoll模型、边缘触发和条件触发记录

时间:2023-07-09 23:44:06浏览次数:42  
标签:触发 epoll 模型 阻塞 描述符 缓冲区 读写

  • 参考:https://blog.csdn.net/liu0808/article/details/52980413
  • epoll模型
    • 三大函数:epoll_create,epoll_wait, epoll_ctl ,是Linux独有的函数,因为它需要linux内核支持。
    • 头文件<sys/epoll.h>
    • epoll_create
      • int epoll_create(int size);
        • 成功时返回epoll文件描述符,失败时返回-1。
        • size:epoll实例的大小。
      • 该函数从2.3.2版本的开始加入的,2.6版开始引入内核。Linux最新的内核稳定版本已经到了5.8.14,长期支持版本到了5.4.70。从2.6.8内核开始的Linux,会忽略这个参数,但是必须要大于0。
    • epoll_ctl
      • int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
        • 成功时返回0,失败时返回-1。
        • epfd --- epoll_create返回的文件描述符。
        • op --- 指定监视对象的操作,如添加、更改、删除等。
          • EPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL
        • fd --- 注册需要受监视的对象的文件描述符。
        • event 监视对象的事件类型。
          • 其中events字段表示要监听的事件类型,可以是以下值之一:
            • EPOLLIN:表示对应的socket缓冲区有数据可读(当又收到了对端的一些数据,就会触发;或者作为服务端时有连接连过来)
            • EPOLLOUT:输出缓冲已为空,表示对应socket缓冲区可写(由于EPOLLLET边缘触发方式更加高效,所以一般都使用边缘触发方式)
            • EPOLLPRI:收到OOB数据的情况(优先级的区别,OOB应该是紧急事件)。
            • EPOLLRDHUP:断开连接或半关闭(有其中一边关闭)的情况,这在边缘触发方式下非常有用。
            • EPOLLHUP:表示文件描述符被挂起
            • EPOLLERR:发生错误。
            • EPOLLET:表示将epoll设置为边缘触发模式。
            • EPOLLONESHOT:设置为一次性事件。发生一次事件后,相应文件描述符不再收到事件通知。需要搭配epoll_ctl函数的二参使用
            • EPOLLCTL_MOD:再次设置事件。
          • data字段表示用户数据,它的类型是一个union,可以存放一个指针或文件描述符等数据。它的定义如下:

            • 其中,ptr可以指向任何类型的用户数据,fd表示文件描述符,u32和u64分别表示一个32位和64位的无符号整数。使用时,用户可以将自己需要的数据存放到这个字段中,当事件触发时,epoll系统调用会返回这个数据,以便用户处理事件。
      • ps:要监视谁,就把谁epoll_ctl处理一下。

    • epoll_wait
      • int epoll_wait(int epfd, struct epoll_event*events,int maxevents,int timeout);
        • 成功时返回发生事件的文件描述符的数目,失败时返回-1。
        • epfd 表示事件发生监视范围的epol例程的文件描述符
        • events 保存发生事件的文件描述符集合的结构体地址值。
        • maxevents 第二个参数中可以保存的最大事件数目。
        • Timeout:以毫秒为单位的等待时间,传递-1时,一直等待直到发生事件。比select的timeout精度低,因此select一般也被用为高精度的定时器。
  • 边缘触发和条件触发,还有IO的阻塞/非阻塞模式(https://blog.csdn.net/liu0808/article/details/52980413
    • Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会每次都通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,则它们每次都会返回,这样就会大大降低你检索自己关心的就绪文件描述符的效率!!!
    • Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!
    • 阻塞IO:当你去读一个阻塞的文件描述符时,如果在该文件描述符上没有数据可读,那么它会一直阻塞(通俗一点就是一直卡在调用函数那里),直到有数据可读。当你去写一个阻塞的文件描述符时,如果在该文件描述符上没有空间(通常是缓冲区满了)可写,那么它会一直阻塞,直到有空间可写。以上的读和写我们统一指在某个文件描述符进行的操作,不单单指真正的读数据,写数据,还包括接收连接accept(),发起连接connect()等操作...
    • 非阻塞IO:当你去读写一个非阻塞的文件描述符时,不管可不可以读写,它都会立即返回,返回成功说明读写操作完成了,返回失败会设置相应errno状态码,根据这个errno可以进一步执行其他处理。它不会像阻塞IO那样,卡在那里不动!!!
    • 几种IO模型的触发方式:
      • select(),poll()模型都是水平触发模式;
      • 信号驱动IO是边缘触发模式;
      • epoll()模型既支持水平触发,也支持边缘触发,默认是水平触发。
    • 通过实际例子来看看epoll的水平出发和边缘触发,以及阻塞IO和非阻塞IO对它们的影响。下面假设水平触发为LT,边缘触发为ET;服务端用于监听的socket文件描述符为sockSrv,accept返回的用于读写客户端的文件描述符为sockCli。(下面不涉及阻塞的sockSrv,因为epoll_wait()返回必定是已就绪的连接,设不设置阻塞accept()都会立即返回。存在特例:设置阻塞的监听sock,当客户端发起连接请求时服务端繁忙没顾上accept,等回头accept时客户端自己已经断开了,此时当服务器到达accept时会发生阻塞。很好理解,客户端发来了消息然后自己毙了,但是服务端并不知道客户端毙了,所以会卡在accept)
      • 1> 水平触发的非阻塞sockSrv
        • 因为水平触发在缓冲区中有可读数据时会在每次epoll_wait提示sockSrv去读,因此都会accept成功。
      • 2> 边缘触发的非阻塞sockSrv
        • 因为边缘触发,在高并发的情况下sockSrv来不及及时处理accept,可能在等待的这段时间内发来了多个可读通知,实际上这些通知被冲抵了,等sockSrv腾出手来处理时它实际上只接收到一个(最后一个),因此它也只会做一次accept,因此会错过一些遗留在缓冲区的信息。当然它可以用循环的方式accept,把缓冲区里的东西读干净再忙别的,但这在代码上无意增加了工作量。
      • 3> 水平触发的阻塞sockCli
        • 单次读取(√):每次只读自己buf缓冲区大小的数据,但因为是水平触发epoll_wait每次都会提醒去读,所以不会落下数据。只有缓冲区有数据时epoll_wait才会提醒sockCli去读,因此也不会阻塞在recv。
        • 循环读取(×):如果是阻塞状态,在不知道要读多少数据时不要用循环读取,因为我们不知道何时该停止,如果没数据可读,它就会阻塞在recv,直到有数据可读。如果这个时候,用另一个客户端去连接,服务器不能受理这个新的客户端!!!
        • 对于写(×),只要输出缓冲区还有空间,水平触发会不断提醒你去写,这很烦;如果写的时候输出缓冲区满了,阻塞的sockCli就会使它阻塞在send那等着空间被腾出来。
      • 4> 水平触发的非阻塞sockCli
        • 单次读取(√):同3的单次读取。
        • 循环读取(乄):非阻塞状态,没数据了就会返回,因此对水平触发的非阻塞sockCli,单次、循环读取都ok。
        • 对于写(乄),只要输出缓冲区还有空间,水平触发会不断提醒你去写,这很烦,你会在就绪描述符里看到很多你不想要的执行写操作的描述符,影响搜索效率,但它没错;还好它不会在写满输出缓冲区时阻塞在send那。
      • 5> 边缘触发的阻塞sockCli
        • 单次读取(×):每次只读自己buf缓冲区大小的数据,就算输入缓冲区还有数据也不管,直到epoll_wait下次发来读信号。有遗留数据,所以会干扰下一个事件。
        • 循环读取(×):同3的循环读取。
        • 对于写(×),如果写的时候输出缓冲区满了,阻塞的sockCli就会使它阻塞在send那等着空间被腾出来。
      • 6> 边缘触发的非阻塞sockCli
        • 单次读取(×):同5的单次读取
        • 循环读取(√):因为不会阻塞,可以通过循环读取输入缓冲区的所有数据,挺好地完成任务。同4的循环读取。
        • 对于写(√),它只会提醒你写一次,且输出缓冲区也不会阻塞在那,非常好,就是要注意用循环写把你这次要写的内容写完。
    • 总结
      • 1.对于监听的sock,最好使用水平触发模式,边缘触发模式会导致高并发情况下,有的客户端会连接不上。如果非要使用边缘触发,网上有的方案是用while来循环accept()。
      • 2.对于读写的sock,水平触发模式下,阻塞和非阻塞效果都一样,不过为了防止特殊情况,还是建议设置非阻塞。其次水平触发模式下不要用循环读取数据,本身输入缓冲区有数据水平触发就会叫个不停,所以别给自己找无谓的麻烦。
      • 3.对于读写的sock,边缘触发模式下,必须使用非阻塞IO,并要一次性全部读写完数据(也就是循环读写)。
  •  

标签:触发,epoll,模型,阻塞,描述符,缓冲区,读写
From: https://www.cnblogs.com/GanSinba/p/17539700.html

相关文章

  • 数学建模一层次分析模型
    层次分析法是对一些较为复杂、模糊的问题做出决策的简易方法这里涉及一个决策概念的理解初步理解应该是一种评价类的模型层次分析法的典型应用:1、用于最佳方案的选取2、用于评价类分析3、用于指标体系的优选层次分析法的名字中层次的原因层次分析法的步骤和方法:1、建立......
  • LLaMA模型指令微调 字节跳动多模态视频大模型 Valley 论文详解
    Valley:VideoAssistantwithLargeLanguagemodelEnhancedabilitY大家好,我是卷了又没卷,薛定谔的卷的AI算法工程师「陈城南」~担任某大厂的算法工程师,带来最新的前沿AI知识和工具,包括AI相关技术、ChatGPT、AI绘图等,欢迎大家交流~。近期基于LLaMA微调的模型有很多,Alpaca,Vi......
  • String内存模型和Java常用方法
    一、String内存模型1、直接赋值创建string对象内存原理:StringTable(串池):字符串常量池,用来存储字符串,只能是在直接赋值中使用才会存在串池当中(JDK7前串池是在方法区里面,StringTable(串池)在JDK7版本开始从方法区中挪到了堆内存,但是运行机制没有发生变化)eg:首先mian方法进栈,创建变......
  • 2023.27 华为云盘古大模型
    2020年11月,华为盘古大模型在华为云内部立项成功,完成了与合作伙伴、高校的合作搭建。2021年,华为盘古大模型也正式对外公布,包括NLP(自然语言处理)、CV(机器视觉)和科学计算大模型;后续又发布了矿山、药物分子、气象、海浪等行业大模型,深入金融、制造、政务、煤矿、铁路等10多个行......
  • 【Proactor模型】事件驱动模型 - Proactor模型简述
    Proactor模型Reactor是非阻塞同步网络模式,而Proactor是异步网络模式。阻塞I/O:当程序执行read,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read才会返回。阻塞等待的是"内核数据准备好"和"数据从内核态拷贝到用户态"这两个过......
  • js select option 选中触发事件
    <HTML><HEAD><script>functioncc(val){alert(val);}</script></HEAD><BODY><formid="formid"><!--下面是得到option中的内容--><!--<selectοnchange=&qu......
  • 【Reactor模型】事件驱动模型 - Reactor模型简述
    Reactor模式Reactor模式是非阻塞同步网络模式,主要由Reactor和处理资源池这两个核心部分组成,负责:Reactor负责监听和分发事件,事件类型包含连接事件,读写事件;处理资源池负责处理事件,如read->处理逻辑->sendReactor模式是灵活多变的,可以应对不同的业务场景,灵活在于:Reactor的数......
  • 用 AIGC 重构后的智能客服,能否淘到大模型时代的第一桶金?
    ChatGPT的诞生打响了现代AI军备竞赛的第一枪。以GPT-4、ChatGTP、Bard等为代表的大语言模型在全球各界引起了广泛关注。结合ChatGPT的底层技术逻辑,未来中短期内ChatGPT产业化的方向大致有四类:即智能客服、文字模态的AIGC应用、代码开发相关工作以及图像生成。其中,最适......
  • Meta 正式开源音乐生成模型 MusicGen
    导读Meta近日在Github上开源了其音乐生成模型MusicGen。据介绍,MusicGen主要用于音乐生成,它可以将文本和已有的旋律转化为完整乐曲。该模型基于谷歌2017年推出的Transformer模型。研发团队表示:“我们使用了20000小时的授权音乐来对训练该模型,并采用Meta的EnC......
  • C++之内存模型
    背景C++内存模型是C++程序中内存管理和数据存储的基础。了解C++内存模型的概念和运作机制对于编写高效、安全的C++代码至关重要。本文将详细介绍C++内存模型的基本概念、内存分配策略以及与其相关的代码示例。C++内存模型的基本概念C++内存模型主要包括以下几个部分:静态存储......