转自:网络
6 ^6 C x/ g+ }: h前言7 _" y q4 I) c2 U3 P
在《Unix网络编程》一书中提到了五种IO模型,分别是:阻塞IO、非阻塞IO、IO复用、信号驱动IO以及异步IO。本篇文章主要介绍IO的基本概念以及阻塞IO、非阻塞IO、IO复用三种模型,供大家参考学习。
4 G& g( s+ f6 A一、什么是IO# J% M- o; C! X( Y8 C
计算机视角理解IO:
: c9 ~" Q+ x. g n对于计算机而言,任何涉及到计算机核心(CPU和内存)与其他设备间的数据转移的过程就是IO。IO对于计算机而言有两层意思:
+ |( ~2 C0 \7 O: ~* X$ ?- X% a; wIO 设备:比如我们最常见的打印机、鼠标、键盘。对IO设备的数据读写。程序视角理解IO:- \$ a! H; M6 C5 A$ c- N3 A& X
现代操作系统将空间划分为用户空间和内核空间。
% j# B8 c4 U; C- n用户空间:非内核应用程序则运行在用户空间。用户空间中的代码运行在较低的特权级别上,不能直接访问内核空间和硬件设备。内核空间:操作系统的核心,是操作系统工作的基础,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。
' J7 ^7 G+ C- C( F5 O) `4 ]) l
ql5413vmpu164068207106.png
' A5 R7 B6 Y5 F* q% n
操作系统为了能够正常平稳地运行下去,它是不会允许应用程序随意访问计算机硬件部分,如内存、硬盘、网卡,应用程序必须通过操作系统提供的API来访问,以达到安全的访问控制。9 a7 k0 y8 y# u, ]* w3 s
总结:IO对于应用程序而言,强调的是通过向内核发起系统调用完成对I/O的间接访问。7 B- S& T w! K& ~ ]1 u5 H
应用程序发起一次IO访问分为两个阶段:
1 y7 [! d5 |0 F) q, [; N' ~IO调用阶段:应用程序向内核发起系统调用。IO执行阶段:内核执行IO操作并返回。数据准备阶段:内核等待IO设备准备好数据数据拷贝阶段:将数据从内核缓冲区拷贝到用户空间缓冲区[/ol]* G1 z5 c4 M: x. ^
i11b33xosan64068207206.png
7 G& p- q9 F9 C2 [- Q- ~& N
4 s5 ]1 H- h! _* R0 f二、阻塞IO模型
2 k: G) |. u( H! N1 I阻塞I/O模型是最常见的IO模型,其流程图如下所示。% l( B. d) g3 C9 O
t5pryauui4u64068207306.png
` D$ M& n n" @5 `3 h. f应用程序发起一个系统调用(recvform),这个时候应用程序会一直阻塞下去,直到内核把数据准备好,并将其从内核复制到用户空间,复制完成后返回成功提示,这个时候应用程序才会继续处理数据。 h9 l D3 e* _: V" T- D
优点:模型简单,实现难度低,适用于并发量较小的应用开发。缺点:IO调用阶段和IO执行阶段都会阻塞。典型的阻塞I/0模型的例子为data=socket.read(),如果内核数据没有准备就绪,Socket线程就会一直阻塞在read()中等待内核数据就绪。' g7 G1 ^: E/ A
生活场景:某天,你跟你女朋友去奶茶店买奶茶,点完奶茶后后,由于你们不知道奶茶什么时候才能做好,所以你们就只能一直等着,其他什么事情也不能干。$ {1 k1 C4 e' ]& P4 C4 ~
三、非阻塞 IO模型; i* U) ]" w/ e, R# v
在非阻塞IO模型中,应用进程需要不断询问内核数据是否就绪,在内核数据还未就绪时,应用进程还可以做其他事情。
: Y: `1 S5 O4 h( N9 P
u1d41hjstrr64068207406.png
) h4 k, T) u- Q; a+ q* H
从上图可以看出, 非阻塞IO模型需要应用进程不断地主动询问内核数据是否已准备好了。8 {( O5 p0 T2 e* Z ~0 S
优点:模型简单,实现难度低;与阻塞IO模型对比,它在等待数据报的过程中,进程并没有阻塞,它可以做其他的事情。缺点:轮询发送 recvform,消耗CPU 资源。生活场景:你和你女朋友去奶茶店买奶茶,吸取了上一次的教训,点完奶茶后顺便去逛了逛商场。由于你们担心会错过取餐,所以你们就每隔一段时间就来问下服务员,你们的奶茶做好了没有,来来回回好多回,若干次后,终于问到奶茶已经准备好了,然后你们就开心的喝了起来。
$ C) H. n$ H2 `) k0 }3 Y+ F6 R; R/ I5 X8 E6 B2 x0 O
四、IO复用模型
% h$ ?! H; b" o J" ~非阻塞IO模型需要进程不断地轮询发起recvform系统调用,就会有很多的线程不断调用recvfrom 请求数据,先不说服务器能不能扛得住这么多线程,就算扛得住那么很明显这种方式是不是太浪费资源了,线程是我们操作系统的宝贵资源,大量的线程用来去读取数据了,那么就意味着能做其它事情的线程就会少。
. W6 q2 L* n' i+ ]& P例如:你是奶茶店的服务员,每个人点好奶茶后,每隔几分钟就来问你一次好了没有,随着问的人越来越多,你可能会开始怀疑人生。那么有没有什么好的解决办法呢?% K6 U% a# f) S& s2 _) J: s8 N
答案:不需要所有进程轮询来发起recvform来查询数据是否已经准备好了,而是有人帮忙来询问,这个帮忙的人就是select。
" F- I% J* c0 H9 O9 i, u9 yIO复用模型如下所示:9 e9 E+ t1 Y2 ^- k g2 O
p4vil5medji64068207506.png
/ u/ p4 \8 y: }/ `多个进程的IO注册到一个复用器(select)上,select 会监听所有注册进来的IO。如果内核的数据报没有准备好,调用select 的进程将会被阻塞,而当任一IO在内核缓冲区中有数据,select调用就会返回可读条件,然后进程再进行recvform系统调用,内核将数据拷贝到用户空间,注意这个过程是阻塞的。1 u% q" {5 T/ h$ P+ d
注意:IO 复用模型在第一个阶段和第二个阶段其实都有阻塞,第一个阶段阻塞于 select 调用,第二个阶段阻塞于数据复制。
4 g6 v& n+ i; M: j- r* B优点:适用于高并发应用程序。缺点:模型复杂,实现、开发难度较大。生活场景:如果每个人都过一会就来问一下奶茶好了没有,奶茶店的压力也太大了。于是奶茶店想到了一个办法,找一个中间人(select)挡在奶茶店前面,顾客(应用进程)询问那个中间人奶茶好了没有(对应多个进程的IO注册到一个复用器(select)上),如果没有好就让顾客等待(应用进程阻塞于 select 调用)。中间人持续查看顾客的奶茶是否准备好,如果有一个人的奶茶准备好了就会去通知那个人可以取了(而当任一IO在内核缓冲区中有数据,select调用就会返回可读条件,然后进程再进行recvform系统调用)。1 \5 o% q' g9 R: B% R! P
ps1zivck3fw64068207606.png
! w! j3 w5 Y# r2 u1 ?
+ M( o' u# v$ X0 U总结
3 s/ \3 W9 S" j5 n' w7 i学习IO模型时,必须要把每个模型联系起来看,比如阻塞IO模型会阻塞较长时间,而非阻塞IO在等待数据报的过程中,进程并没有阻塞,它可以做其他的事情。IO复用模型可以很好的降低服务器的压力,且在连接数众多且消息体不大的情况下有很大的优势。——EOF——你好,我是飞宇,本硕均于某中流985 CS就读,先后于百度搜索、字节跳动电商以及携程等部门担任Linux C/C++后端研发工程师。: q% B! T" i4 |2 T
最近跟朋友一起开发了一个新的网站:编程资源网,已经收录了不少资源(附赠下载地址),如果屏幕前的靓仔/女想要学习编程找不到合适资源的话,不妨来我们的网站看看,欢迎扫码下方二维码白嫖~( N+ ^8 c& q" O2 P, q+ X- U
bm0lqlrihpx64068207707.gif
! H6 {( v2 P4 d! t( f6 l3 s
; n) L: C! Q' X3 R0 L }, V' B同时,我也是知乎博主@韩飞宇,日常分享C/C++、计算机学习经验、工作体会,欢迎点击此处查看我以前的学习笔记&经验&分享的资源。6 q* y( z& Z. F# Q# O" L4 x
我组建了一些社群一起交流,群里有大牛也有小白,如果你有意可以一起进群交流。% @0 B' N k' B2 }
g4vwlq1cfhx64068207807.png
. c. Z; E! c) _' n欢迎你添加我的微信,我拉你进技术交流群。此外,我也会经常在微信上分享一些计算机学习经验以及工作体验,还有一些内推机会。
# K" i1 w: {3 x) T: c
os32gzewtga64068207907.png
& \% \9 h; O; C; m% S/ Q) w0 m加个微信,打开另一扇窗6 p, N n3 N) S
gjbu1yyj2tp64068208007.gif
4 L( E- z: w1 h4 @; n& I8 W- `& a. t% d4 |' K
C/C++98
. F4 F k" M- h- ]- M6 K% h6 Y+ N程序员的那些事儿93 ]8 ?/ P& p, I0 U; C, k4 n: M* d8 R
C/C++ · 目录
& f# S; Y% p% t/ Z( B: d" s
9 E2 c, x9 ]0 \7 V上一篇美国政府敦促开发者:停止使用 C、C++ |