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能够支持高并发也是由于使用了异步非阻塞处理模型,本文将用通俗的话讲解异步.同步.阻塞.非阻塞的区别 ...
随机推荐
- 尴尬:在Excel中为指定数据插入饼图失败
本来是非常非常简单的一个需求,即便不会,随便百度下也都有说明. 可自己却在一次紧急工作中因此耽误了时间,需求是需要插入一个饼图但因操作错误一直无法正确显示饼图数据,非常尴尬,干脆记录下这一刻. 尴尬1 ...
- Window Server+IIS配置实现一台服务器绑定多个HTTPS证书
参考原文链接:https://blog.csdn.net/lengyiqiu/article/details/89182239 此处做个记录防止丢失: 直接上步骤: 1.选安装好SSL证书,供下面配置 ...
- 从零开始的react入门教程(九),react context上下文详解,可能有点啰嗦,但很想让你懂
壹 ❀ 引 我在从零开始的react入门教程(八),redux起源与基础用法一文中,介绍了redux的前辈Flux,以及redux关于单项数据更新的基本用法.我们在前文提到,相对Flux支持多个sto ...
- 当我忘记SQL怎么写的时候,我……
当我忘记SQL怎么写的时候,我-- 以往的我,打开电脑百度一番,打开笔记查询一轮,发现没找到我最想要的 不要慌,问题不大 后来发现MySQL本身就带有帮助文档. 于是我一顿操作:win+R >& ...
- 从零开始手写 mybatis (三)jdbc pool 从零实现数据库连接池
前景回顾 第一节 从零开始手写 mybatis(一)MVP 版本 中我们实现了一个最基本的可以运行的 mybatis. 第二节 从零开始手写 mybatis(二)mybatis interceptor ...
- RFID EPC Class1 Gen2电子标签笔记
RFID EPC Class1 Gen2 符合EPC Class1 Gen2(简称G2)协议V109版的电子标签(Tag)和读写器(Reader)应该具有下述的特性 标签存储器分区 Tag memor ...
- 【framework】DisplayContent简介
1 前言 DisplayContent 用于管理屏幕,一块屏幕对应一个 DisplayContent 对象,虽然手机只有一个显示屏,但是可以创建多个 DisplayContent 对象,如投屏时, ...
- Vuex和普通全局对象
Vuex中的核心方法 Vuex是一个专为Vue.js应用程序开发的状态管理模式,其采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.每一个Vuex应用的核心就是 ...
- comm命令
comm命令 comm命令用于比较两个已排过序的文件,该命令会一列列地比较两个已排序文件的差异,并将其结果显示出来,如果没有指定任何参数,则会把结果分成3列显示:第1列仅是在第1个文件中出现过的列,第 ...
- leetcode - 中序遍历
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 . 示例 1: 输入:root = [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root = [] 输出:[] 示例 ...