面试题答案
一键面试阻塞IO和非阻塞IO在数据读取或写入操作时的行为差异
- 阻塞IO:
- 数据读取:当应用程序调用阻塞IO的读操作时,内核会等待数据准备好,在数据未准备好之前,应用程序会一直阻塞,无法执行其他代码。例如在一个TCP套接字上调用
read
函数,如果接收缓冲区中没有数据,线程会被挂起,直到有数据可读。 - 数据写入:同样,在调用阻塞IO的写操作时,如果内核缓冲区已满,无法立即接收应用程序要发送的数据,应用程序也会阻塞,直到内核缓冲区有足够空间来接收数据。
- 数据读取:当应用程序调用阻塞IO的读操作时,内核会等待数据准备好,在数据未准备好之前,应用程序会一直阻塞,无法执行其他代码。例如在一个TCP套接字上调用
- 非阻塞IO:
- 数据读取:非阻塞IO的读操作会立即返回。如果数据尚未准备好,读操作会返回一个错误(例如
EWOULDBLOCK
或EAGAIN
),应用程序不会被阻塞,可以继续执行其他代码。应用程序需要通过轮询等方式不断检查数据是否准备好。 - 数据写入:非阻塞IO的写操作也是立即返回。如果内核缓冲区没有足够空间接收所有数据,写操作会返回已写入的字节数,应用程序需要再次调用写操作,直到所有数据都被写入。
- 数据读取:非阻塞IO的读操作会立即返回。如果数据尚未准备好,读操作会返回一个错误(例如
即时通讯服务器中采用非阻塞IO相比于阻塞IO在处理大量客户端连接时的性能提升
- 提高并发处理能力:阻塞IO下,一个线程在处理一个客户端连接的IO操作时会被阻塞,无法同时处理其他客户端。而非阻塞IO可以让一个线程在同一时间轮询多个客户端连接的IO状态,一旦某个连接的数据准备好,就可以处理该连接的数据,大大提高了并发处理能力,能够同时处理大量客户端连接。
- 资源利用率提升:在阻塞IO模式下,线程长时间阻塞等待IO操作完成,造成线程资源的浪费。非阻塞IO可以减少线程的阻塞时间,使线程可以在等待IO的间隙执行其他任务,提高了CPU等资源的利用率。
- 响应速度加快:对于即时通讯服务器,快速响应客户端的消息至关重要。非阻塞IO可以及时处理多个客户端的消息,避免因单个客户端的IO阻塞而导致其他客户端消息处理延迟,从而提高整个系统的响应速度。
即时通讯服务器中采用非阻塞IO相比于阻塞IO在处理大量客户端连接时编程复杂度变化
- 复杂度增加:
- 轮询机制:非阻塞IO需要应用程序自己实现轮询机制,以不断检查各个客户端连接的IO状态。例如使用
select
、poll
或epoll
等多路复用技术,这些技术的使用增加了代码的复杂度,需要开发者熟悉相关函数的参数和返回值处理。 - 状态管理:由于非阻塞IO的读、写操作可能不会一次完成,应用程序需要自己管理每个连接的读写状态,例如记录已经读取或写入了多少数据,以便在后续轮询中继续处理,这增加了状态管理的复杂度。
- 错误处理:非阻塞IO会返回各种错误(如
EWOULDBLOCK
),开发者需要仔细处理这些错误,正确区分是真正的错误还是暂时的资源不可用,增加了错误处理的复杂度。
- 轮询机制:非阻塞IO需要应用程序自己实现轮询机制,以不断检查各个客户端连接的IO状态。例如使用
- 复杂度降低(相对方面):在阻塞IO模式下,如果要处理大量客户端连接,通常需要为每个连接创建一个线程,这会带来线程创建、销毁和线程间同步的开销和复杂度。非阻塞IO模式下可以使用少量线程处理大量连接,从线程管理角度看,一定程度上降低了编程复杂度。