IO模型就是说IO的方式都是通过模型而实现。在说IO模型之前,先说一个重要的前提:IO分两步,等待与拷贝。等待是为了等文件描述符就绪,拷贝就是拷贝数据。
目录
讲故事
在说五种IO之前,先讲一个故事吧。
有一个宿舍,里面住着比较特殊的五个人,张三,李四,王五,赵六,田七。他们都饿了,于是去食堂吃饭,食堂只有一个窗口,五种饭菜,五个厨师分别做,他们都想吃,而且带回去吃。
张三去之后,点了五个菜,但是每个菜做好之后,都要自己打包,于是张三就在窗口等着,啥也不干,好了一个菜就自己打包。
李四去之后,带了个手机,点菜之后,就玩手机,过一段时间,就问,老板好了没,没好就继续玩手机,好了自己就去打包。
王五去之后,带了铃铛和手机,点菜之后,把铃铛往那一放,对老板说,好一个你就按一下,于是开始玩手机,直到铃铛响了,自己就来打包。
赵六去之后,先把饭堂的窗口从一个改成五个,然后从第一个开始在那来回走,好一个就自己打包一个。
田七去都没去,直接打电话交了外卖,做好了让外卖送过来,自己偷偷学习。
完。
IO模型
故事讲完,其实这五个人分别对应了一种IO模型。五个IO模型分别是,阻塞IO、非阻塞IO、信号驱动IO、多路转接/多路复用IO、异步IO。张三就是阻塞IO,自己干等,程序也是这样,在这里阻塞着,不进行后面的操作;李四就是非阻塞,如果IO还没有就绪,就做点别的事情,待会再来问;王五就是信号驱动IO,程序调用IO之后,就继续干其他事情,IO就绪,就会发个信号,表示IO就绪;赵六就是多路转接IO,这个IO比较特殊,待会细说;田七就是异步IO,这个就是让操作系统帮忙等,自己先忙别的。
说一下几个关键字:就绪,通俗理解就是准备好了。
读就绪:文件内有数据
写就绪:文件内有空余空间
这里操作的都是文件描述符,所以缓冲区等都已文件来描述。
拷贝:把数据从内核空间拷贝到用户空间。
上面用很浅显的例子介绍了五种IO,但是不太深刻,适用于了解,下面分别说一下。
-
阻塞IO
阻塞IO是最常见的IO,在内核将数据准备好之前,系统调⽤会⼀直等待。所有的套接字,默认都是阻塞⽅式。
-
非阻塞IO
⾮阻塞IO: 如果内核还未将数据准备好, 系统调⽤仍然会直接返回, 并且返回EWOULDBLOCK错误码。⾮阻塞IO往往需要程序员循环的⽅式反复尝试读写⽂件描述符, 这个过程称为轮询。
-
信号驱动IO
信号驱动IO:内核将数据准备好的时候,使⽤SIGIO信号通知应⽤程序进⾏IO操作。
-
异步IO
先说异步,再说多路转接,因为多路转接比较特殊。
异步IO: 由内核在数据拷⻉完成时, 通知应⽤程序,注意属于信号驱动IO的区别,信号驱动是告诉应⽤程序可以开始拷⻉数据。异步IO是别人拷贝,信号驱动IO是自己拷贝。
-
多路转接IO
多路转接前面基本没有介绍。多路转接是适用于要监控多个文件描述符的时候。例如上面的故事,别人都是 1 个窗口,但是赵六需要照顾六个窗口。它在一些方面上提高了效率,因为原理其实还是一个阻塞IO,只是可以监控多个文件描述符。
拿select举例:(select函数是实现多路复⽤输⼊/输出模型的一种)
重要概念
到这里五种IO模型就介绍完了,但是具体的多路转接没有细说,在下一篇博文继续说。这里先说明几个重要的概念:
-
同步与异步
同步与前面的同步与互斥不是一个概念。从前面的故事来体现就是看这个饭是不是自己打包。张三,李四,王五,赵六都是自己打包,因此这就是同步,田七是叫的外卖,别人帮忙打包,因此是异步。于是回到这里就是:
同步:数据的拷贝由自己完成,也就是说调用之后,不是立即返回而是有数据之后,才返回,这就是同步
异步:数据的拷贝由操作系统完成,然后通知调用者,数据已经拷贝好,可以开始处理这就是异步。
-
阻塞与非阻塞
阻塞:对比张三,一直等,啥也不做,这在操作系统称为挂起/阻塞。
非阻塞:对比李四,在没有饭时,还能玩玩手机,也就是线程或者进程没有在系统调用时被挂起,这就是非阻塞。