透视I/O多路复用
透视I/O多路复用
我写的不是select
这些函数的教学,需要了解的请自行Google或者去man
,这些是帮助我理解函数的封装之下的道理。
需要回答的问题
I/O准备好了指什么?什么叫I/O已经可读/写?
内核如何开始监视?监视的模式如何?
内核以何种机制通知进程?
内核/用户态搬运数据的效率?
阻塞非阻塞?
什么是I/O多路复用
I/O多路复用(multiplexing)是一种单进程,单线程监视多个文件描述符(file descriptor)的软件机制。和多进程/多线程的服务方式不同,I/O多路复用将仅有的单进程阻塞起来,有一个关注的描述符集合,内核在检测到集合中有准备好读写的描述符后唤醒进程,进行I/O操作。
现在首先回答第一个问题——怎么叫做I/O准备好了?
Linux文档中是这么定义的:
A file descriptor is considered ready if it is possible to perform a corresponding I/O operation (e.g., read(2) without blocking, or a sufficiently small write(2)).
此外,read
和fread
是默认的“blocking calls”,也就是说当没有可读的数据时进程将转为blocked阻塞状态直到有数据读。
在网络编程中,一个socket(Unix里,socket无差别地是文件描述符)可读的条件是:
- socket内核接收缓存区中的字节数大于或等于其低水位标记SO_RCVLOWAT。此时可以无阻塞地读该socket,并且读操作返回的字节数大于0。
- socket通信对方关闭连接。此时对该socket读操作将返回0。
- 监听socket上有新的连接请求。
- socket上有未处理的错误。此时我们可以使用getsockopt来读取和清除该错误。
可写的条件是:
- socket内核发送缓冲区中的可用字节数大于或等于其低水位标记SO_SNDLOWAT。此时我们可以无阻塞写该socket,并且写操作返回的字节数大于0。
- socket写操作被关闭。对写操作被关闭的socket执行写操作将触发一个SIGPIPE信号。
- socket使用非阻塞connect连接成功或者失败(超时)之后。
- socket上有未处理的错误。此时我们可以使用getsockopt来读取和清除该错误。
SO_RCVLOWAT和SO_SNDLOWAT是每个socket的两个指标,标识了缓冲超过某个值内核才通知进程socket可读。
列举这些诸条的用意是认识到,系统内核有明确的方式和指标对I/O的状态做判断,发现I/O准备好后及时通知进程。
我们已经对进程需要何种I/O有了准确的答案,现在回到定义,进程和内核之间的协作如何开展开?这里便引出了2、3两个问题。
I/O多路复用的实现
1. select/poll
的实现
select
在调用时调用每一个要监视的fd的poll回调(不是那个系统调用),需要知道,每一个fd有一个队列用来存放所有监视它的进程,这个回调的作用就是给fd的这个队列,叫做struct wait_queue_head_t
,加入新的监视者。这是select
的准备工作,到此为止,如果路上遇到了可用的fd那么直接返回,否则进程就可以安心睡会了。
此时,如果受监视的fd上有感兴趣的事情发生(比如字符写入),fd会遍历它的struct wait_queue_head_t
,唤醒这些监视它的进程——仅仅是唤醒。接下来的事情是进程来做,它重复之前的迭代查询,遍历它的参数集子,确定所有 ready的fd,收集到返回值里面去,进程并不知道是谁唤醒的它,需要再检查的。那么问题3也就得到回答——内核简单唤醒进程,再丢给进程去挨个查询就好。
看着熟悉啊,这不就是visitor模式么?
poll
在select
的基础上取消了最大fd数量的限制。其实,在内核文件linux/posix_types.h中有声明曰#define __FD_SETSIZE 1024
,当然,可以通过重新编译内核手工突破这个限制。
2. epoll
的实现
问题4是一个涉及效率的讨论。select/poll
机制中,当监视的fd数量巨大时,select
维护的是一个超大的数据结构,伴随fd数量的增加,成本达到了O(N)级别,此外每次调用时向内核传参数、传出内核消息需要内存拷贝又是一笔开销。epoll
就是一个解决此问题的出现,适用大量fd同时监听。
顾名思义,epoll_ctl
意指control,执行它是对常驻内核中的数据结构(红黑树)进行增减操作,而不是每次等待时都传进全部fd。epoll_ctl
还为相应的fd注册回调函数,事件发生,内核将fd插入一张链表当中,返回给用户。
为什么I/O多路复用?
I/O多路复用适用于多个文件描述符同时监听的情况。下面基于这一情景。
这首先要聊清楚什么是阻塞不阻塞的I/O(问题5)。阻塞I/O在没有输入时会将进程阻塞,直到读到数据才返回,然而非阻塞I/O在这些不好的情况下会返回一个标识错误的码,保证了进程流畅的进行下去。
前面讲过read
的默认阻塞行为,那么对于一个没有足够输入的fd,read会将进程阻塞在这一个fd上,大写的不好。
考虑把read
开成非阻塞式,那么会需要一个循环来不断尝试读,也就是所谓busy waiting,大概长这个样子:
while(true)
{
non-blocking read fd1;
non-blocking read fd2;
...
}
busy waiting坏处就是长时间占据CPU还可能读不到数据。
用select
解决这个问题。循环地在几个fd上阻塞,注意I/O多路复用可以同时在多个fd上阻塞,既满足了多路监听,又有阻塞式的低CPU占用。代码长类似这样:
while(true)
{
select_result = select(fds);
for(auto fd : select_result) deal with fd;
}
最后,现在是时候看一下讲了这么久的“多路复用”到底是什么了。wiki上是这么解释的:
In telecommunications and computer networks, multiplexing (sometimes contracted to muxing) is a method by which multiple analog or digital signals are combined into one signal over a shared medium. The aim is to share an expensive resource.
多路复用在一个昂贵的设备上组合了多路信号,放在I/O多路复用上就是,用一个阻塞式I/O函数监听多个感兴趣的fd。
此外需要注意,I/O多路复用获得ready的fd并不代表接下来的一切读写都不会阻塞(比如读一个超过SO_RCVLOWAT=100的socket,要从大小为1000的buffer发2000的数据,自信的调阻塞I/O的话就死在这了——当然从select
的角度讲大可以阻塞I/O直接上),所以该和非阻塞合作的还是要设为非阻塞!
透视I/O多路复用的更多相关文章
- Python(七)Socket编程、IO多路复用、SocketServer
本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" ...
- 你真的会玩SQL吗?透视转换的艺术
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- Lind.DDD.RedisClient~对StackExchange.Redis调用者的封装及多路复用技术
回到目录 两雄争霸 使用StackExchange.Redis的原因是因为它开源,免费,而对于商业化的ServiceStack.Redis,它将一步步被前者取代,开源将是一种趋势,商业化也值得被我们尊 ...
- IO多路复用概念性
sellect.poll.epoll三者的区别 先来了解一下什么是进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行,这种行为为进程的切换,任务切换 ...
- python学习笔记-(十四)I/O多路复用 阻塞、非阻塞、同步、异步
1. 概念说明 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可 ...
- Open xml 操作Excel 透视表(Pivot table)-- 实现Excel多语言报表
我的一个ERP项目中,客户希望使用Excel Pivot table 做分析报表. ERP 从数据库中读出数据,导出到Excel中的数据源表(统一命名为Data),刷新Pivot table! 客户还 ...
- EXCEL 2010学习笔记 —— 数据透视表
今天整理一下EXCEL2010 数据透视表的课程笔记,数据透视表可以对多组数据进行统计和整理,是一种基本的数据可视化工具. 记录6个方面的总结: 1.创建数据透视表 2.更改数据透视表的汇总方式 3. ...
- 【CSS3进阶】酷炫的3D旋转透视
之前学习 react+webpack ,偶然路过 webpack 官网 ,看到顶部的 LOGO ,就很感兴趣. 最近觉得自己 CSS3 过于薄弱,想着深入学习一番,遂以这个 LOGO 为切入口,好好研 ...
- IO多路复用之select总结
1.基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程.IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/ ...
随机推荐
- JAVA开发环境搭建 - JDK安装及环境变量配置
1.前提条件 系统:本教程以WIN7系统为例 JDK:本教程以jdk-7u79-windows-x64为例 2.安装步骤 双击运行JDK安装程序
- Java对象序列化的使用和定制
序列化的概念及使用场合 序列化就是把对象转化为字节序列并持久化保存,可以保存在内存中.磁盘文件系统,甚至通过网络传递,并能够在以后将这个字节序列完全恢复为原来的对象. 对象序列化的概念引入Java是为 ...
- hudson入门
持续集成hudson入门博客分类: Java 单元测试配置管理maven项目管理Tomcat 极限编程中一项建议实践便是持续集成,持续集成是指在开发阶段,对项目进行持续性自动化编译.测 ...
- Springboot启动源码详解
我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static voi ...
- grpc-gateway:grpc对外提供http服务的解决方案
我所在公司的项目是采用基于Restful的微服务架构,随着微服务之间的沟通越来越频繁,就希望可以做成用rpc来做内部的通讯,对外依然用Restful.于是就想到了google的grpc. 使用grpc ...
- 向php提交数据及json
php中提交表单有两种方法,即: (1)利用表单提交 例: <form action="php文件名" method='提交方式'> username:<inpu ...
- Triangle Problems
Triangle Problem songxiuhuan 宋修寰 Import the Junit and eclemma Choose the project and right click, ch ...
- 一个很逗的东西——Jd
这个嘛是本人专门为了NOI上面对拍程序写的对拍程序,已经经历了NOI2015的考验:更重要的是——纯Pascal的哦(HansBug:其实是我不会写.sh脚本TT,谁叫用惯了windows的我只会写b ...
- c++ string 对象操作
字符串转换大小写如下: #include "stdafx.h" #include <iostream> #include <string> using na ...
- python list 切片实验
list[start:stop:step] >>> a_list=['hito','bb','cc','dd','ee','ff']>>> a_list[::-1] ...