什么是IO?
IO=input output,在单片机上是对MCU管脚电平的输入与输出;在linux上便是对文件的输入与输出;多路IO复用,也便是多个文件的输入输出同时监控
\\\插播一条:

自己在今年整理一套单片机物联网开拓资料大全(附送网盘链接)
C措辞根本+电路板设计+数模电+开拓工具
Linnux+51+stm32+stm8实战项目代码
事理图+源代码+先容视频+作品讲解
想要的同学私信找我。
io是很多Java / python / go开拓职员的重灾区,如果平时开拓没打仗过,可能就只知道个壅塞/非壅塞、同步/异步,厉害一点的再来个多路复用
很多同学对这些观点根本没有明确的理解,真便是朗读并背诵全文~
本日,我就带着你探索一下io的发展史,往后再有人问你io,那他便是纯纯踢到钢板上了
网络上关于io的文章弗成偻指算,但是下面这段话你可能是第一次看到(看得懂就看,看不懂就跳过,该你懂的时候自然会懂):
不管是windows还是linux,所有牵扯到 io的操作,都无法由运用程序直接完成,把文件操作权限开放给用户是很危险的,想实行io操作,必须利用操作系统内核供应的函数,但这些函数不须要我们亲自调用,Java已经帮我们做好了封装,我们在开拓时调干系api即可,如下图这两个包
io便是大略的read / write,而nio引入三个新的观点:
·Buffer:数据容器;
·Channel:这个东西太抽象了,中文名叫通道,知道通过它能完成内核间的io操作就行;
·Selector:nio实现多路复用的根本;
ok废话说完,我们先把干系观点梳理清楚
.同步或异步:同步即有序运行,当前任务实行完,才会实行下个任务;异步则相反,其他任务不须要等待当前任务实行完,常日依赖事宜、回调机制来实现任务间次序关系;
.壅塞与非壅塞:在进行壅塞操作时,当前哨程会处于壅塞状态,无法从事其他任务,只有当条件就绪才能连续,比如数据读取、写入;而非壅塞则是不管 IO操作是否结束,直接返回。
光看观点脑瓜子嗡嗡的吧,没紧要,请看大屏幕~
干饭
公司附近有家网红饭店,每天去他们家用饭的小姐姐特殊多,当然你不要误解我的意思,我是想说他们家饭很好看,啊…不对,我的意思是他们家小姐姐很好吃,啊呸…也不对
总之我常常去,期间我的点餐办法经历了以下几个版本:
·v1.0:刚开始去的时候看别人都在排队点餐,身为诚笃人的我只能等前面人点完了再点,然后去取餐口等着取餐,有时候须要等15分钟才会取到餐,但是在取餐口站着可以看到更多小姐姐,以是最初也没在意;
·v2.0:后面某一天创造取餐口上面有一个屏幕,显示了当前的取餐号顺序,哇我恍然大明白,从那开始,我每次点完餐就找个小姐姐多的地方坐着,每隔5分钟就来取餐口看下是否轮到我取餐;
·v3.0:久而久之,每天看小姐姐也看腻了,有一天创造桌子上有个二维码,哇我又恍然大明白,原来可以扫码点餐啊,而且通过扫码点的餐,做事员会把餐送到你的位置;
取餐和io之间的关系:
v1.0(bio,blocking io):排队点餐、等餐,类似bio,同步壅塞,线程提交io操作后,在io操作完成前不能返回,也不能去干其它事,只能憨憨地等;
v2.0(nio,non-blocking io):排队点餐,时时时去取餐口查看是否轮到自己取餐,类似nio,同步非壅塞,线程提交io操作后可以先返回,但是须要主动找操作系统获取结果(nio可以构建多路复用io,这是本文的重点);
v3.0(nio2,或者叫aio,asynchronous io):扫码点餐,点好餐后找个位置坐着看小姐姐即可,餐好了做事员会送过来,类似aio,异步非壅塞,在nio根本上增加了事宜和回调机制,操作系统准备好数据后,会主动关照线程。
关于操作系统对付io到nio的函数支持,演化过程比较繁芜,你须要先搞懂操作系统如何实现零拷贝
关于io / nio,实在就上面这点东西,千万别被绕晕了,本日我们的主题是多路复用io
老规矩,先抛几个兄弟们最最最常见的迷惑,这些迷惑不才文都会找到答案:
·什么是多路复用?
·为什么须要多路复用?
·多路复用办理了什么问题?
·到底什么是多路复用,复用的是什么?
传统的网络通信都是利用socket,流程如下:
.创建socket
.将当前做事器ip和端口绑定到socket
.监听端口,通过accept处理要求
流程来看没啥毛病,但是你要知道,accept是壅塞的,也便是说同时只能处理一个要求,如果你想同时处理多个,可以用多线程,但这样又会引发另一个问题:操作系统中的线程多了后,须要耗费大量资源来管理线程和高下文切换(这里啰嗦一句,不管什么场景,线程并不是越多越好,到达某个阈值后,线程越多效率反而越低)
以是,想优雅地同时处理多个要求,操作系统内核必须实现单个线程监听多个socket,即 io多路复用
linux系统对多路复用的支持有三种:
·多路复用:select
·多路复用pro:poll
·多路复用pro max:epoll
来看看这三种函数的实现,关于他们三个的性能也就大概清楚了
干系视频推举
口试中正经“八股文”网络事理tcp/udp,网络编程epoll/reactor
6种epoll的设计,让你吊打口试官,而且他不能还嘴
epoll事理阐发以及三握四挥的处理
LinuxC++后台做事器开拓架构师免费学习地址
【文章福利】:
//返回值是已就绪文件描述符个数
int select (int __nfds, fd_set __readfds, fd_set __writefds, fd_set __exceptfds, struct timeval __timeout)
参数阐明:
?_ _nfds:监听的文件描述符数量(不要纠结文件描述符是什么东西,能够理解成每个io操作都对应一个文件描述符);
?_ _readfds、__writefds、__exceptfds:指定多路复用机制监听的事宜类型,这三个分别是读数据事宜、写数据事宜、非常事宜;
?_ _timeout:监听时壅塞等待的超时时长;
select通过监听多个文件描述符来管理多个连接,一次能监听1024个(默认值),当select函数返回后,遍历描述符汇合找到已就绪的描述符进行下一步处理
至此,一个线程只能管理一个连接的痛点算是占领了,但还存在两个问题:
?每次监听的描述符数量有限,虽然能够通过修正宏文件修正,但这种做法太极度;
?我们必要不断实行select函数来获取已就绪的文件描述符,遍历过程也必要耗费cpu性能;
以是linux引入了poll,占领文件描述符限定的问题
poll
//返回值也是已就绪文件描述符个数
int poll (struct pollfd __fds, nfds_t __nfds, int __timeout);
参数阐明:
?_ _fds:pollfd布局体数组,包含了要监听的文件描述符和要监听的事宜类型;
?_ _nfds: pollfd布局体数组的数量,没有大小限定;
?_ _timeout:监听时壅塞等待的超时时长;
相对付select,poll实在就打破了文件描述符的限定,但依然必要我们遍历每个文件描述符来检测是否就绪
绿色图标【‟で】liutianwang123
以是,Linux2.6引入了epoll
epoll
epoll有三个函数epoll_create、epoll_ctl和 epoll_wait
//创建epoll实例,size表示监听多少个文件描述符
int epoll_create(int size);
//将连接加入epoll监听列表,参数分别表示:
//epoll_create()的返回值
//须要实行的修正操作
//须要监听的文件描述符
//监听的事宜类型
int epoll_ctl(int epfd, int op, int fd, struct epoll_event event);
//壅塞等待返回已就绪的文件描述符,参数分别表示:
//epoll_create()的返回值
//事宜的凑集
//events大小
//超时时间
int epoll_wait(int epfd, struct epoll_event events, int maxevents, int timeout);
epoll模型支持自定义监听的描述符数量,也可以直接返回就绪的描述符
大名鼎鼎的redis在Linux系统的实现便是用的epoll模型,以是纵然是单线程,也能轻松应对高并发的客户端访问
说了这么多,那到底什么是io多路复用?复用的是什么?
这两个问题我以为很难阐明,可能等往后真正打仗到操作系统层面的知识了,才会真正悟透吧
个人对付复用的意见:
首先肯定不是对socket的复用,一个要求对应一个socket耶稣来了也改变不了;
也不是对线程的复用,但彷佛也可以这么理解,由于毕竟是一个线程管理多个socket;
所谓复用,可能并不是非得复用某一个东西,我以为是通过一次到内核的要求实现对多个socket的管理这个行为
关于上面提到的各种函数理解即可,不用太深入研究,我也是翻了好些文档才得到这些信息,没必要在上面花太多韶光,不然脑瓜子嗡嗡的~,我现在脑瓜子就嗡嗡的,果真谛解越多不睬解就越多。。。
ok我话说完