当前位置:嗨网首页>书籍在线阅读

36-IO多路复用

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

2.10 I/O多路复用

应用通常需要在多个文件描述符上阻塞:在键盘输入(stdin)、进程间通信以及很多文件之间协调I/O。基于事件驱动的图形用户界面(GUI)应用可能会和成百上千个事件的主循环竞争[5]

如果不使用线程,而是独立处理每个文件描述符,单个进程无法同时在多个文件描述符上阻塞。只要这些描述符已经有数据可读写,也可以采用多个文件描述符的方式。但是,要是有个文件描述符数据还没有准备好——比如发送了read()调用,但是还没有任何数据——进程会阻塞,而且无法对其他的文件描述符提供服务。该进程可能只是阻塞几秒钟,导致应用效率变低,影响用户体验。然而,如果该文件描述符一直没有数据,进程就会一直阻塞。因为文件描述符的I/O总是关联的(比如管道),很可能一个文件描述符依赖另一个文件描述符,在后者可用前,前者一直处于不可用状态。尤其是对于网络应用而言,可能同时会打开多个socket,从而引发很多问题。

试想一下如下场景:当标准输入设备(stdin)挂起,没有数据输出,应用在和进程间通信(IPC)相关的文件描述符上阻塞。只有当阻塞的IPC文件描述符返回数据后,进程才知道键盘输入挂起——但是如果阻塞的操作一直没有返回,又会发生什么呢?

如前所述,非阻塞I/O 是这种问题的一个解决方案。使用非阻塞I/O,应用可以发送I/O请求,该请求返回特定错误,而不是阻塞。但是,该方案效率不高,主要有两个原因:首先,进程需要连续随机发送I/O操作,等待某个打开的文件描述符可以执行I/O操作。这种设计很糟糕。其次,如果进程睡眠则会更高效,睡眠可以释放CPU资源,使得CPU可以处理其他任务,直到一个或多个文件描述符可以执行I/O时再唤醒进程。

下面我们一起来探讨I/O多路复用。

I/O多路复用支持应用同时在多个文件描述符上阻塞,并在其中某个可以读写时收到通知。因此,I/O多路复用成为应用的关键所在,在设计上遵循以下原则。

1.I/O多路复用:当任何一个文件描述符I/O就绪时进行通知。

2.都不可用?在有可用的文件描述符之前一直处于睡眠状态。

3.唤醒:哪个文件描述符可用了?

4.处理所有I/O就绪的文件描述符,没有阻塞。

5.返回第1步,重新开始。

Linux提供了三种I/O多路复用方案:select、poll和epoll。本章先探讨select和poll,epoll是Linux特有的高级解决方案,将在第4章详细说明。