IO模式——同步(阻塞、非阻塞)、异步

时间:2022-09-09 21:13:41

为什么IO模式很重要?因为现代的计算机和操作系统的架构决定了CPU是稀缺资源,大家都要来一起竞争,而IO(特别是网络相关的IO)的速度往往较慢。所以如何进行IO就有了多种模式,包括同步、异步、阻塞、非阻塞等等。


不少人把这几个概念放到一起讨论,很多时候也难以区分。


这里从根上剖析下该怎么看待这几个概念。


首先,异步和同步是相对的,而同步情况下又有阻塞和非阻塞之分。


异步很容易理解。当用户程序需要进行IO的时候,发出IO请求,然后就立刻返回,可以继续做其它事情。

例如,从网络收包,当包抵达后放到内核某个缓存区,并且从内核空间放置到程序需要的用户空间后(一种是直接复制,比较费资源;一种是映射mmap),通知程序,程序之后就可以处理数据了。

这是最理想的模式,CPU干活效率最高。


同步情况则是,当用户程序需要进行IO的时候,发出IO请求,然后就等着数据到达后进行处理(首先将数据从内核空间复制到用户空间,然后进行操作)。

具体怎么等呢?一种就是阻塞在那里,CPU就处理其它的程序去了;一种就是发现没有数据就返回一个错误,程序可以干点别的事情(通常是不断轮询),过会还得自己主动回来看看数据OK了么。


同步情况下显然效率比较差,于是有了各种技术来改进它,一种就是IO多路复用(用一个专门的线程来负责IO),包括Linux上的select、poll和epoll。

select和poll类似,都是用一个内核优化线程来不断轮询IO,一旦有数据了用户程序就可以利用系统调用将数据从内核空间复制到用户空间,之后进行处理。这虽然提高了效率,但其实仍然是一种同步模式。

epoll则更进一步,采用了底层的notify机制和mmap,底层数据可用后通知IO线程,并利用mmap将数据直接映射到用户空间。此时用户程序可以直接对数据进行操作了。