五种网络IO模型总结
概述
在网络上看到很多关于阻塞IO、非阻塞IO、同步IO、异步IO的例子,总觉得写的过于复杂并且让人难以理解。于是我把我自己把这几个概念的理解写下来以供参考。
POSIX
POSIX(可移植操作系统接口)把同步IO操作定义为导致进程阻塞直到IO完成的操作,反之则是异步IO
I/O 操作一般分为两个部分:
- 阶段1:应用程序发起 I/O 操作请求,等待数据,或者将要操作的数据拷贝到系统内核中(比如 socket)。
- 阶段2:系统内核进行 I/O 操作(一般是内核将数据拷贝到用户进程中)。
简述阻塞、非阻塞、同步、异步
阻塞和非阻塞
阻塞和非阻塞发生在请求处,也就是阶段1 ,关注的是程序在等待调用结果时的状态。
阻塞是指调用结果返回之前,当前进程(线程)会被挂起,调用进程(线程)会阻塞在IO请求处,直到IO操作请求完成,数据到来,最重要的是用户进程的函数在请求过程中不会返回。
- eg:recv()函数默认是阻塞的,什么是阻塞呢?就是当你调用recv()函数时,整个进程或者线程就等待在这里了,直到你recv的fd的所有信息都被send过来,这么做好处就是保证所有信息都能够完整的读取了,但劣势也很明显,就是在recv()的过程中你的进程或线程做不了其它事情,由此,引入了非阻塞IO。
非阻塞调用是指在不能立刻得到结果之前,该调用不会阻塞进程(线程),进程(线程)可以去干别的事情,一般使用轮询的方法来查询IO操作的数据是否准备好了。
- eg:以recv()函数为例,当你将其设置为非阻塞时,每次当你recv()时,就直接返回,不管信息有没有完全send进来,好处很明显,recv()了之后进程马上能处理下一行代码,坏处也很明显,就是你不知道你的消息是否读完了,这种问题就是TCP中大名鼎鼎的半包问题(解决办法主要是通过一个buffer缓存所有读进来的消息)
当使用I/O 多路复用的时候,用户的 I/O 操作会立即返回,但会利用 select 和 epoll 等方法对所监视的 I/O 操作描述符进行遍历轮询(此操作是为了检查数据是否准备完毕,也就是 I/O 操作的阶段1,同时此操作是阻塞,进程或者线程需要等待轮询结果的返回),查看可用的句柄并返回。然后用户进程再对其进行操作。
同步/异步IO
- 同步和异步关注的是消息通信机制,具体来说就是调用者是否等待调用结果的返回,对于 I/O 操作而言,就是应用程序是否等待 I/O 操作完成。
- eg: 以recv()函数为例, 不管 是否设置为阻塞还是非阻塞(阶段1),都有一个将内核数据拷贝到用户进程的I/O操作(阶段2),如果用户进程等待I/O操作返回,则为同步,反之则为异步。
同异步io和阻塞非阻塞io的区别
结合前面的概念,可以看出,其实这两者存在本质的区别,它们的修饰对象是不同的。
- 阻塞和非阻塞是指进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪。
- 同步和异步是指访问数据的机制,同步一般指主动请求并等待 I/O 操作完毕的方式,当数据就绪后在读写的时候必须等待,异步则指主动请求数据后便可以继续处理其它任务,随后等待 I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。
只有同步的时候,才会有是否阻塞之说。
IO多路复用
这里在调用recv
前先调用select
或者poll
,这两个个系统调用都可以在内核准备好数据(网络数据到达内核)时告知用户进程,这个时候再调用recv
一定是有数据的。因此这一过程中它是阻塞于select
或poll
,而没有阻塞于recv
,有人将非阻塞IO定义成在读写操作时没有阻塞于系统调用的IO操作(不包括数据从内核复制到用户空间时的阻塞,因为这相对于网络IO来说确实很短暂),如果按这样理解,这种IO模型也能称之为非阻塞IO模型,但是按POSIX来看,它也是同步IO,称之为同步非阻塞IO。
这种IO模型比较特别,分个段。因为它能同时监听多个文件描述符(fd)。当有文件描述符有就绪事件时,则返回就绪事件的文件描述符来进行读写。
异步
调用aio_read
,让内核等数据准备好,并且复制到用户进程空间后执行事先指定好的函数。整个过程没有recv
,这才是真正的异步IO。
信号驱动
通过调用sigaction
注册信号函数,等内核数据准备好的时候系统中断当前程序,执行信号函数(在这里面调用recv
)。是不是很像异步IO?很遗憾,它还是同步IO(省不了数据从内核拷贝到用户空间的操作)。
总结比较下五种IO模型
总结
IO分两阶段:
1.数据准备阶段
2.内核空间复制回用户进程缓冲区阶段
一般来讲:阻塞IO模型、非阻塞IO模型、IO复用模型(select/poll/epoll)、信号驱动IO模型都属于同步IO,因为阶段2是阻塞的(尽管时间很短)。只有异步IO模型是符合POSIX异步IO操作含义的,不管在阶段1还是阶段2都可以干别的事。
ps:以上图片均截自UNIX网络编程卷1。
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2020/12/iomodels/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接