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能够支持高并发也是由于使用了异步非阻塞处理模型,本文将用通俗的话讲解异步.同步.阻塞.非阻塞的区别 ...
随机推荐
- Nginx的反向代理做负载均衡
对于一个大型网站,随着网站的访问量快速增长,单台服务器很难再支撑起需要,所以我们会购置多个服务器来满足业务量的需求,然后再利用Nginx提供的反向代理功能,来实现多台服务器间的协作功能,提高网站的处理 ...
- DNS正向解析
实验介绍:正向解析 通常把域名到IP称为正向解析 把ip到域名称为反向解析 一:前期准备 准备一台客户端测试正向解析是否正常 修改ip 子网掩码 DNS服务器 使用VMnet8 IP要和DNS服务器端 ...
- ASP.NET Core分布式项目实战(oauth2与open id connect 对比)--学习笔记
任务14:oauth2与open id connect 对比 以微博开放平台为例(微博登录接入--授权机制): https://open.weibo.com/wiki/授权机制 可以看到微博登录接入使 ...
- NC16541 [NOIP2013]车站分级
题目链接 题目 题目描述 一条单向的铁路线上,依次有编号为1, 2, -, n 的n 个火车站.每个火车站都有一个级别,最低为1 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次 ...
- 【Unity3D】广告牌特效
1 前言 广告牌特效是指:空间中的一个 2D 对象始终(或尽可能)面向相机,使得用户能够尽可能看清楚该 2D 物体.广告牌特效一共有以下 3 种: 正视广告牌:广告牌始终以正视图姿态面向相机,即广 ...
- Java并发编程实例--5.线程睡眠
有时候我们需要让线程在一段时间内不做任何事.例如某线程每个一小时检测一下传感器,剩余的时间不做任何事. 我们可以使用sleep()方法使线程睡眠,此期间不占用计算机资源. 这个方法接受一个整数表示睡眠 ...
- SuspendThread and ResumeThread
记录下,用于复现 #include <windows.h> #include <iostream> LRESULT CALLBACK WndProc(HWND hWnd, UI ...
- win32-WH_KEYBOARD的使用
我们使用WH_KEYBOARD来禁用记事本的ALT的按键 .cpp #include <Windows.h> #include <stdio.h> #include <t ...
- 麒麟系统开发笔记(十一):在国产麒麟系统上使用gdb定位崩溃异常方法流程进阶定位代码行数及专项测试Demo
前言 上一篇,通过研究,可以定位到函数,本篇进一步优化,没有行数,程序较为复杂的时候,就无法定位,所以进一步定位. 本篇做了qBreakpad的研究,但是没有成功,过程也还是填出来,后来突然注意 ...
- C#程序全局异常处理—WPF和Web API两种模式
C#程序的全局异常处理,网上搜下资料都是一大堆,我这里最近也是独立做一个B/S结构的小项目, 后面又增加了需求用WPF实现相同的功能,这里将我所使用的全局异常处理方式做一个简短的总结分享. Web A ...