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能够支持高并发也是由于使用了异步非阻塞处理模型,本文将用通俗的话讲解异步.同步.阻塞.非阻塞的区别 ...
随机推荐
- 基于OpenCV-Python的图像位置校正和版面分析
前言 使用opencv对图像进行操作,要求:(1)定位银行票据的四条边,然后旋正.(2)根据版面分析,分割出小写金额区域. 图像校正 首先是对图像的校正 读取图片 对图片二值化 进行边缘检测 对边缘的 ...
- MarkDown文件插入图片(绝对\相对路径\调整图像大小位置)
1. 插入网络图片(有效网络连接) Markdown中插入图片的语法为,图片路径可以直接写入图片有效链接网址即可: 方法1:![图片说明](图片有效链接网址) 方法2:<img src=&quo ...
- 基本数据类型(primitive type)
数据类型 数据类型分为基本数据类型(primitive type)和引用数据类型(reference type) 基本数据类型(primitive type) 数值类型 整数类型 浮点类型 字符类型 ...
- 哈希表(HashMap)与字符串哈希
哈希表 哈希表是一种通过映射来快速查找的数据结构.其通过键值对(key-value)来存储.一个数据通过哈希函数的运算来生成一个属于他自己的键值,尔后将其与键值绑定.当我们想查找这个数据时,就可以直接 ...
- 使用lvs实现ftp的负载均衡
操作系统:CentOS6.5_x64 问题描述 使用lvs实现ftp的负载均衡 为了使模型足够简单,这里只实现了loadblance,HA并未实现,可以借助keepalived实现. 具体实现 hos ...
- NC15445 wyh的吃鸡
题目链接 题目 题目描述 最近吃鸡游戏非常火,你们wyh学长也在玩这款游戏,这款游戏有一个非常重要的过程,就是要跑到安全区内,否则就会中毒持续消耗血量,我们这个问题简化如下 假设地图为n*n的一个图, ...
- Centos中报错apt Command not Found
先说结论: 在centos下用yum install xxxyum和apt-get的区别: 一般来说著名的linux系统基本上分两大类: RedHat系列:Redhat.Centos.Fedora等 ...
- 用ELK分析每天4亿多条腾讯云MySQL审计日志(2)--EQL
上一篇介绍了用ELK分析4亿多条审计日志过程,现在介绍如何用Python3分析ES的程序 需要分析的核心库审计数据: 1,950多张表,几十个账号, 2,5种操作类型(select,update,in ...
- Java集合框架学习(十五) ListIterator接口详解
ListIterator介绍 一个为list对象设计的迭代器,允许开发人员在2个方向上迭代,修改和获得list迭代位置. ListIterator 没有所谓当前元素. 它的游标位置总是位于previo ...
- QT - Day 5
1 event事件 用途:用于事件的分发 也可以做拦截操作,不建议 bool event( QEvent * e); 返回值 如果是true 代表用户处理这个事件,不向下分发了 e->ty ...