透视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/ ...
随机推荐
-
google tensorflow guide
# For CPU-only version $ pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow- ...
-
lintcode二叉树的锯齿形层次遍历 (双端队列)
题目链接: http://www.lintcode.com/zh-cn/problem/binary-tree-zigzag-level-order-traversal/ 二叉树的锯齿形层次遍历 给出 ...
-
GIS公交查询-flex/java
开发语言是flex.java,开发平台是myeclise.eclise,开发接口是arcgis api for flex,提供以下的功能: 1.站名-站名查询: 2.站点查询: 3.路线查询: 备注: ...
-
clion windows 开发配置
1.下载clion 并且安装. 地址 : http://download-cf.jetbrains.com/cpp/clion-1.0.1.exe 2.安装cygwin 地址: https://cy ...
-
Android Studio下打jar包
在我们使用Eclipse时,我们常常使用的第三方类库文件大多都是jar包形式,用起来很方便.但是jar包只能打包class文件,对于Android UI类库而言,我们常常需要打包资源文件,对于界面不多 ...
-
UIScrollView中添加一个视图,实现让其始终固定在某个位置
ScrollView中添加一个视图,实现让其始终固定在某个位置,如最底部的位置.方法是自定义一个继承UIScrollView,重写它的layoutSubviews方法.代码如下: #import &q ...
-
MySQL基础知识-安装MySQL
前导: 昨天去参加了一个面试,公司不太大,是一家日资企业,在国内有几家分公司,面试官问到了MySQL的基本操作和性能优化,说了一大堆,倒是比较轻松的过了,但是面试结束之后,想了一下,基本操作忘的还是挺 ...
-
copy与mutableCopy的区别总结
1.不可变类型(不管是集合还是非集合),copy结果,不产生新对象,浅拷贝:不可变类型(不管是集合还是非集合),mutableCopy结果,产生新对象,深拷贝.2.可变类型(不管是集合还是非集合),c ...
-
Android中,如何提升Layout的性能?
Layout 是 Android 应用中直接影响用户体验的关键部分.如果实现的不好,你的 Layout 会导致程序非常占用内存并且 UI 运行缓慢.Android SDK 带有帮助你找到 Layout ...
-
HTML的简介
1.HTML语言是做显示用的.HTML文件由浏览器来转译执行.(全站工程师:全都会.) 2.静态网页由HTML(显示).CSS(修饰).JAVAScript(简单交互)三种元素构成.3.动态网页:数据 ...