何为I/O多路转接?
I/O多路转接,先构造一张我们感兴趣的描述符(通常都不止一个)的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I/O时,该函数才返回。poll、pselect和select这三个函数使我们能够执行I/O多路转接。在从这些函数返回时,进程会被告知哪些描述符已准备好可以进行I/O。
为什么要引入该技术呢?
通过read,我们可以从流中读入数据;通过write,我们可以往流写入数据。现在假定一个情形,我们需要从流中读数据,但是流中还没有数据,(典型的例子为,客户端要从socket读如数据,但是服务器还没有把数据传回来),这时候该怎么办?
通常做法有两种,第一,阻塞;第二,非阻塞轮询。两种做法都有不可避免的弊端。阻塞I/O一个线程只能处理一个流的I/O事件。如果想要同时处理多个流,要么多进程(fork),要么多线程(pthread_create),两种方法效率都不高。非阻塞忙轮询的I/O方式,浪费CPU时间。
为了避免CPU空转,可以引进了一个代理(一开始有一位叫做select的代理,后来又有一位叫做poll的代理,不过两者的本质是一样的)。这个代理比较厉害,可以同时观察许多流的I/O事件,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流。这就是I/O多路转接产生的原由。
select和poll函数使我们可以执行I/O多路转接。select,poll,epoll各自的优缺点又是什么呢?为何共存了多种使用I/O多路转接的技术?
简单而言,对于监听的大多数流都会发生读写操作时,使用select比较高效,只有少部分流有读写操作时,epoll比较高效。因为select在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流。我们从select那里仅仅知道了,有I/O事件发生了,但却并不知道是那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。无差别轮询同时处理的流越多,每一次轮询时间就越长。select有这种缺陷,所以后面诞生了epoll,epoll会把哪个流发生了怎样的I/O事件通知我们。
原文地址:https://www.cnblogs.com/qianxuan/p/11172466.html