IO 多路复用原理
IO 多路复用
普通情况下,一个进程只能监视一个文件描述符(阻塞),如果使用非阻塞 IO,则会使 CPU 频繁陷入内核和空转,降低效率。而IO 多路复用是操作系统提供的接口,他会帮你同时监视多个 fd,当fd没有事件发生,调用这个接口的用户进程会阻塞,当有事件发生时,返回事件发生的 fd。这样就实现了一个进程处理多个请求。那 IO 多路复用是如何实现的?
前置知识
等待队列
在Linux内核中等待队列有很多用途,可用于中断处理、进程同步及定时。我们在这里只说,进程经常必须等待某些事件的发生。等待队列实现了在事件上的条件等待:希望等待特定事件(在本文中就是 fd 的可读可写事件)的进程把自己放进合适的等待队列,并放弃控制权(挂起)。因此,等待队列表示一组睡眠的进程,当某一条件为真时,由内核唤醒它们。
Linux 的 wakeup&callback 机制
linux(2.6+)内核的事件wakeup callback机制,这是IO多路复用机制存在的本质。Linux 通过等待队列来管理所有等待socket 某个事件的进程。等待的进程会被阻塞在等待队列上,当事件发生时,内核会遍历这个队列,检查如果某个节点进程关心这个事件,则调用这个进程节点的 call back 函数。
select/poll
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
- 每次调用 select,用户需要传入所有关心的 socket ,CPU 陷入内核,操作系统需要将文件描述符拷贝到内核空间。
- 内核依次检查每个 socket:把 current 轮流挂到各个 fd 的设备等待(fd)队列上,在fd有事件发生,会唤醒等待队列上的进程,此时 current 被唤醒,当进程唤醒后,将就绪事件结果保存在fds的res_in、res_out、res_ex。这个过程的时间是 O(n)。
- 最后检查所有 fds 的res_in、res_out、res_ex,将有事件发生的 fd 拷贝到用户传入的 fb_set 结构体数组,用户遍历找到可读文件描述符。为了效率,操作系统限制拷贝的 BitsMap 大小默认为 1024。
poll 用动态数组取代 BitsMap 但本质不变,对于每个文件描述符的检查复杂度都是 O(n)。
epoll
epoll 有 3 个接口:
epoll_creat创建一个 epoll 描述符
epoll_ctl动态更新关心的文件描述符
epoll_wait 等待关心的 socket 事件发生
首先epoll 和 poll 不一样点是 用户不是在调用 epoll_wait 的时候才传入 fd,而是 epoll_ctl 的时候就已经传入,内核负责保存 fd,这样就省掉了不必要的重复拷贝。epoll_ctl 的同时会把 current 挂在对应 fd 的等待队列并设置回调函数。
每次调用poll系统调用,操作系统都要把current(当前进程)挂到fd对应的所有设备的等待队列上,可以想象,fd多到上千的时候,这样挂法很费事;而每次调用epoll_wait则没有这么啰嗦,epoll只在epoll_ctl时把current挂一遍(这第一遍是免不了的)并给每个fd一个命令:“好了就调回调函数”,如果设备有事件了,通过回调函数,去epoll 的红黑树查找对应节点,并将节点放在 rdllist 双向链表中。而每次调用epoll_wait就只是收集rdllist里的fd就可以了——epoll巧妙的利用回调函数,实现了更高效的事件驱动模型。
epoll 通过 Linux 的回调机制,socket事件发生时Linux 内核会通过回调函数去epoll 的红黑树查找对应节点,并将节点放在 ready_list 双向链表中。最后返回这个双向链表,用户只需遍历这个链表即可得到所有就绪的socket。
边缘触发ET和水平触发LT
- 使用边缘触发模式时,当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中苏醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只苏醒一次,因此我们程序要保证一次性将内核缓冲区的数据读取完;
- 使用水平触发模式时,当被监控的 Socket 上有可读事件发生时,服务器端不断地从 epoll_wait 中苏醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据需要读取;
一般来说,边缘触发的效率比水平触发的效率要高,因为边缘触发可以减少 epoll_wait 的系统调用次数,系统调用也是有一定的开销的的,毕竟也存在上下文的切换。
参考:
9.2 I/O 多路复用:select/poll/epoll | 小林coding (xiaolincoding.com)
https://www.xiaolincoding.com/os/8_network_system/selete_poll_epoll.html
poll&&epoll实现分析(一)——poll实现-lvyilong316-ChinaUnix博客
poll&&epoll实现分析(二)——epoll实现-lvyilong316-ChinaUnix博客
IO 多路复用原理的更多相关文章
- IO多路复用原理
(1)IO multiplexing(2)用在什么地方?多路非阻塞式IO.(3)select和poll(4)外部阻塞式,内部非阻塞式自动轮询多路阻塞式IO IO多路复用原理:其实就是整个函数对外表现为 ...
- IO多路复用原理&场景
目录 IO多路复用的历史 阻塞 IO 非阻塞 IO IO 多路复用 select poll epoll IO多路复用高效的原因 IO多路复用解决的什么问题 epoll比selector性能一定更好吗 ...
- 理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO
完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同 ...
- socket_server源码剖析、python作用域、IO多路复用
本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...
- python之IO多路复用
在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...
- IO多路复用的几种实现机制的分析
http://blog.csdn.net/zhang_shuai_2011/article/details/7675797 select,poll,epoll都是IO多路复用的机制.所谓I/O多路复用 ...
- 转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】
下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架, ...
- I/O模型系列之五:IO多路复用 select、poll、epoll
IO多路复用之select.poll.epoll IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. 应用:适用于针 ...
- IO多路复用和local概念
一.local 在多个线程之间使用threading.local对象,可以实现多个线程之间的数据隔离 import time import random from threading import T ...
- 异步、非阻塞和IO多路复用总结
Nginx是并发处理框架的代表者,很多后台业务都会放在Nginx容器中运行,以实现高吞吐,而Nginx能够支持高并发也是由于使用了异步非阻塞处理模型,本文将用通俗的话讲解异步.同步.阻塞.非阻塞的区别 ...
随机推荐
- Git企业开发控制理论和实操-从入门到深入(七)|企业级开发模型
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...
- 万字手撕AVL树 | 上百行的旋转你真的会了吗?【超用心超详细图文解释 | 一篇学会AVL】
说在前面 今天这篇博客,是博主今年以来最最用心的一篇博客.我们也很久没有更新数据结构系列了,几个月前博主用心深入的学习了这颗二叉平衡搜索树,博主被它的查找效率深深吸引. AVL树出自1962年中的一篇 ...
- uni-app+vue3会遇到哪些问题
已经用 uni-app+vue3+ts 开发了一段时间,记录一下日常遇见的问题和解决办法 uni-app 中的单端代码 uni-app 是支持多端,如果你想让你的代码,只在部分平台使用,那么就需要用的 ...
- 正则表达式,js、javascript 的 replace 的坑,严重留意。
一致以来我以为js的 replace 是全部替换的,没想到是只替换第一个,使用时要严重留意. 举例: let wokao: string = "abc + a_b_c + a.b.c&quo ...
- ESP8266 ESP-01S模块使用及AT命令
ESP-01S PIN定义 工作时连线方法 ESP-01S USB2TTL/MCU GND GND TX(GPIO1) RX RX(GPIO3) TX 3.3V 3.3V 相关文件下载 固件及烧录软件 ...
- 【Lua】Lua基础语法
1 Lua 简介 Lua 是一个小巧的脚本语言,用标准C语言编写而成,由巴西里约热内卢天主教大学的 Roberto Ierusalimschy.Waldemar Celes 和 Luiz Henr ...
- CSS加JS实现网页返回顶部功能
最近在设计自己的博客,前端页面在内容很多的时候往下拖动会有滚动条.通常我们都需要一个返回顶部的功能来实现快速来到网页顶部.当然实现方式不止一种,这里我采用的最实用的一种.使用CSS+Jquery方式 ...
- 在D2D环境下与GDI结合加载位图
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <Windows.h& ...
- 阿里云 SMS 短信 Java SDK 封装
Github & Issues: https://github.com/cn-src/aliyun-sms 官方文档:https://help.aliyun.com/document_deta ...
- Linux开端---Centos
Linux-Centos 虚拟化所需工具:https://pan.baidu.com/s/1643-kYcx9oPGnGEZM1pLOw?pwd=g0v5 提取码:g0v5 问题解决 正常注册网络适配 ...