目录

  • 1、前言
  • 2、内核空间、用户空间、同步、异步、阻塞、非阻塞
  • 3、同步阻塞 IO
  • 4、同步非阻塞IO
  • 5、多路复用
    • 5.1 select
    • 5.2 poll
    • 5.3 epoll

1、前言

  应用进程和内核之间的数据交互方式一直在演进,下面我们对各种形态的交互方式进行介绍。在这之前,我们先明确几个概念:内核空间用户空间同步异步阻塞非阻塞

2、内核空间、用户空间、同步、异步、阻塞、非阻塞

2.1 内核空间
  操作系统单独拥有的内存空间为内核空间,这块内存空间独立于其他的应用内存空间,除了操作系统,其他应用程序不允许访问这块空间。但操作系统可以同时操作内核空间和用户空间。
2.2 用户空间
  单独给用户应用进程分配的内存空间,操作系统和应用程序都可以访问这块内存空间。
2.3 同步
  调用线程发出同步请求后,在没有得到结果前,该调用就不会返回。所有同步调用都必须是串行的,前面的同步调用处理完了后才能处理下一个同步调用。
2.4 异步
  调用线程发出异步请求后,在没有得到结果前,该调用就返回了。真正的结果数据会在业务处理完成后通过发送信号或者回调的形式通知调用者。
2.5 阻塞
  调用线程发出请求后,在没有得到结果前,该线程就会被挂起,此时CPU也不会给此线程分配时间,此线程处于非可执行状态。直到返回结果返回后,此线程才会被唤醒,继续运行。划重点:线程进入阻塞状态不占用CPU资源。
2.6 非阻塞
  调用线程发出请求后,在没有得到结果前,该调用就返回了,整个过程调用线程不会被挂起。

3、同步阻塞 IO

  同步阻塞IO模式是Linux中最常用的IO模型,所有Socket通信默认使用同步阻塞IO模型。同步阻塞IO模型中,应用线程在调用了内核的IO接口后,会一直被阻塞,直到内核将数据准备好,并且复制到应用线程的用户空间内存中。

优点:
并发量较少的网络通信场景较高效
应用程序开发简单

缺点:
不适合并发量较大的网络通信场景

4、同步非阻塞IO

  同步非阻塞IO是同步阻塞IO的一种变种IO模式,它和同步阻塞区别在于,应用线程在向内核发送IO请求后,内核的IO数据在没有准备好的时候会立刻给应用线程返回一个错误代码(EAGAIN 或 EWOULDBLOCK),在内核的IO数据准备好了之后,应用线程再发起IO操作请求时候,内核会在将IO数据从内核空间复制到用户空间后给应用线程返回正常应答。常见的Non-Blocking模式的Socket网络通信就是同步非阻塞模式。

优点:
在内核IO数据准备阶段不会阻塞应用线程,适合对线程阻塞敏感的网络应用

缺点:
轮询查询内核IO数据状态,耗费大量CPU,效率低
需要不断轮序,增加开发难度

5、多路复用


  多路复用是目前大型互联网应用中最常见的一种IO模型,简单说就是应用进程中有一个IO状态管理器,多个网络IO注册到这个管理器上,管理器使用一个线程调用内核API来监听所有注册的网络IO的状态变化情况,一旦某个连接的网络IO状态发生变化,能够通知应用程序进行相应的读写操作。多路网络IO复用这个状态管理器,所以叫多路复用模式。多路复用本质上是同步阻塞,但与传统的同步阻塞多线程模型相比,IO 多路复用的最大优势是在处理IO高并发场景时只使用一个线程就完成了大量的网络IO状态的管理工作,系统资源开销小。
多路复用的基本工作流程:
1、应用程序将网络IO注册到状态管理器;
2、状态管理器通过调用内核API来确认所管理的网络IO的状态;
3、状态管理器探知到网络IO的状态发生变化后,通知应用程序进行实质的同步阻塞读写操作。
  目前Linux主要有三种状态管理器:select,poll,epoll。epoll是Linux目前大规模网络并发程序开发的首选模型,在绝大多数情况下性能远超select和poll。目前流行的高性能Web服务器Nginx正式依赖于epoll提供的高效网络套接字轮询服务。但是,在并发连接不高的情况下,多线程+阻塞I/O方式可能性能更好。

5.1 select

  select是最古老的多路复用模型,Linux在2.6版本之前仅提供select模式,一度是主流的网络IO模式。select采取定期轮询的方式将自己管理的所有网络IO对应的文件句柄发送给内核,进行状态查询,下面是内核系统对应用程序提供的API:

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

  fd_set是一个Long的数组的数据结构,用于存放的是文件句柄(file descriptor)。这个API有三个关键参数,即readset/writeset/exceptset,前两个参数是注册到select,所有需要监听的网络IO文件句柄数组,第三个参数是一个空数组,由内核轮询所有网络IO文件句柄后,将状态有变化的文件句柄值写入到exceptset数组中,也就是说readset/writeset是输入数据,exceptset是输出数据。最后,内核将变化的句柄数数量返回给调用者。

从接口的细节,我们可以看到归纳下select的工作流程:
1、应用线程将需要监视的网络IO文件句柄注册到select状态监视器;
2、select状态监视器工作线程定期调用内核API,将自己所有管理的文件句柄通过(readset/writeset)两个参数传给内核;
3、内核轮询所有传进来的文件句柄的网络IO状态,将有变化的文件句柄值写入exceptset数组中,并且将变化的句柄数数量返回给调用者;
4、select工作线程通知应用程序进行实质的同步阻塞读写操作。
select机制的特性分析:
1、每次调用select,都需要把readset/writeset集合从用户空间态拷贝到内核空间,如果readset/writeset集合很大时,那这个开销很大;
2、每次调用select都需要在内核遍历传递进来的所有文件句柄,每次调用都进行线性遍历,时间复杂度为O(n),文件句柄集合很大时,那这个开销也很大;
3、内核对被监控的文件句柄集合大小做了限制,X86为1024,X64为2048。

5.2 poll

  poll模型和select模型非常类似,状态监视器同样管理一批网络IO状态,内核同样对传输过来的所有网络IO文件句柄进行线性轮询来确认状态,唯一区别是应用线程传输给内核的文件句柄数组不限制大小,解决了select中说道的第三个问题,其他两个问题依然存在。

int poll(struct pollfd *fds, nfds_t nfds, int timeout);typedef struct pollfd {int fd;                         // 需要被检测或选择的文件描述符short events;                   // 对文件描述符fd上感兴趣的事件short revents;                  // 文件描述符fd上当前实际发生的事件
} pollfd_t;
5.3 epoll

  epoll在Linux2.6内核正式提出,是基于事件驱动的I/O方式,相对于select来说,epoll文件句柄没有个数限制,将应用程序关心的网络IO文件句柄的事件存放到内核的一个事件表中,在用户空间和内核空间的copy只需一次。epoll内核和网络设备建立了订阅回调机制,一旦注册到内核事件表中的网络连接状态发生了变化,内核会收到网络设备的通知,订阅回调机制替换了select/poll的轮询查询机制,将**时间复杂度从原来的O(n)降低为O(1),**大幅提升IO效率,特别是在大量并发连接中只有少量活跃的场景。
Linux提供的三个epoll的API:

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

  epoll在内核内存里建了一个红黑树用于存储epoll_ctl传来的连接,epoll内核还会建立一个rdllist双向链表,用于存储网络状态发生变化的文件句柄,当epoll_wait调用时,仅仅观察这个rdllist双向链表里有没有数据即可,有数据就返回,没有数据就让epoll_wait睡眠,等到timeout时间到后即使链表没数据也返回。因为epoll不像select/poll那样采取轮询每个连接来确认状态的方法,而是监听一个双向链表,在连接数很多的情况下,epoll_wait非常高效。

  所有添加到epoll中的网络连接都会与设备(如网卡)驱动程序建立回调关系,也就是说相应连接状态的发生时网络设备会调用回调方法通知内核,这个回调方法在内核中叫做ep_poll_callback,它会把网络状态发生变化的变更事件放到上面的rdllist双向链表中。
  epoll的epoll_wait调用,有EPOLLLT和EPOLLET两种触发返回模式,LT是默认的模式,更加安全,ET是“高速”模式,更加高效:
水平触发(LT):默认工作模式,即当epoll_wait检测到某网络连接状态发生变化并通知应用程序时,应用程序可以不立即处理该事件;下次调用epoll_wait时,会再次通知此事件;
边缘触发(ET): 当epoll_wait检测到某网络连接状态发生变化并通知应用程序时,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次通知此事件。
epoll机制的特性分析:
1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听超过10万个连接);
2、通过epoll_ctl方法将网络连接注册到内核,不用每次查询连接状态时将所有网络文件句柄传输传输给内核,大幅提高效率;
3、内核和网络设备建立事件订阅机制,监听连接网络状态不使用轮询的方式,不会随着文件句柄数目的增加效率下降,只有活跃可用的文件句柄才会触发回调函数;Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关;
4、利用MMAP内存映射技术加速用户空间与内核空间的消息传递,减少复制开销。

Linux的IO模型 —— 多路复用(select、poll、epoll)相关推荐

  1. java nio原理 epoll_多路复用 Select Poll Epoll 的实现原理(BIO与NIO)

    BIO blocking阻塞的意思,当我们在后端开发使用的时候,accetp 事件会阻塞主线程. 当accept事件执行的时候,客户的会和服务建立一个socket 连接.一般后端就会开启一个线程执行后 ...

  2. IO多路复用select,poll epoll以及区别

    看这个一次读懂 Select.Poll.Epoll IO复用技术 文章来简单理解下,如果不是很明白的话,可以参考下面转的知乎上面白话文列子 作者:Leslie 链接:https://www.zhihu ...

  3. 网络编程(三):Linux 网络IO模型、select、pool、epoll 内核设计

    Linux网络IO模型 同步和异步,阻塞和非阻塞 同步和异步 关注的是调用方是否主动获取结果 同步: 同步的意思就是调用方需要主动等待结果的返回 异步: 异步的意思就是不需要主动等待结果的返回,而是通 ...

  4. python3 异步 非阻塞 IO多路复用 select poll epoll 使用

    有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...

  5. IO多路复用select/poll/epoll详解以及在Python中的应用

    IO multiplexing(IO多路复用) IO多路复用,有些地方称之为event driven IO(事件驱动IO). 它的好处在于单个进程可以处理多个网络IO请求.select/epoll这两 ...

  6. Python异步非阻塞IO多路复用Select/Poll/Epoll使用

    来源:http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理 ...

  7. python poll_python IO 多路复用 select poll epoll

    select select 原理 select 是通过系统调用来监视着一个由多个文件描述符(file descriptor)组成的数组,当select()返回后,数组中就绪的文件描述符会被内核修改标记 ...

  8. socket 编程篇六之IPO多路复用-select poll epoll

    http://blog.csdn.net/woxiaohahaa/article/details/51498951 文章参考自:http://blog.csdn.net/tennysonsky/art ...

  9. select poll epoll IO操作多路复用及猴子补丁

    一:select(能监控数量有限,不能告诉用户程序具体那个连接有数据) select目前几乎所有的平台都支持,其良好的跨平台支持也是一个优点 select的缺点在于单个进程能够监控的文件描述的数量存在 ...

最新文章

  1. Scala 深入浅出实战经典 第96讲:Akka第一个案例动手实战main方法实现中ActorSystem等代码详解...
  2. infer的用法_typescript高级用法之infer的理解与使用
  3. DPKG命令与软件安装、APT
  4. express ajax分页实例,element+express+mongoose实现分页查询
  5. 基于消息队列的分布式事务解决方案
  6. YBTOJ洛谷P2223:软件开发(费用流)
  7. js的深浅拷贝( 赋值后原值被覆盖的问题 )
  8. 5g通用模组是什么_中国移动联合芯讯通发布5G终端、芯片及测试产业报告
  9. c++导出标准win32格式的dll
  10. C++之运算符重载(前置++和后置++)
  11. 计算机网络在我国的发展,04. 当前现状ISP典型架构 计算机网络在我国的发展
  12. 求1-50的偶数和,和奇数和
  13. 证书服务器web注册,无法通过 Web 注册请求证书 - Windows Server | Microsoft Docs
  14. Eclipse + Spring + maven Building a RESTful Web Service ---需要添加注释
  15. PHP学习笔记--函数
  16. 部分相机和相机镜头的参数
  17. 查看mysql汉字占用的字节数_一个汉字在数据库占几个字节
  18. 可汗学院公开课——统计学学习:12-34
  19. 利用 Pyecharts 制作饼图
  20. (凯思奥2020-03月)问题记录3,GUI问题记录3 4,国际化异常,微信平台接入 = 数据库修改 + 自动化填充 + 前后端接口修正 + 联调测试问题 + 微信与数字账号绑定 + 思考+部署

热门文章

  1. 【调制解调】QPSK信号的调制解调附matlab代码
  2. centos os u盘启动盘_U盘安装CentOS
  3. Minecraft 1.16.5模组开发(五十二) 修改原版生物战利品 (Loot Table)
  4. 博通平台下实现QinQ功能
  5. AutoGPT - 全自动人工智能助手
  6. buuctf babyrop
  7. ceph mds dmaged造成cephfs崩掉的灾难性恢复
  8. windows添加本地DNS方法
  9. 服务注册与发现(Nacos)
  10. CAN总线加终端电阻的原因