设为首页 | 加入收藏 | OA登陆 | 返回旧网站
中文版 | ENGLISH

NEWS

Android开发

(022)84236606
当前位置:主页 > Android开发 >
高机能IO模子浅析
发布时间:2017-07-10 10:00 来源:http://www.techolics.com

高机能IO模子浅析

处事器端编程常常必要结构高机能的IO模子,常见的IO模子有四种:

(1)同步阻塞IO(Blocking IO):即传统的IO模子。

(2)同步非阻塞IO(Non-blocking IO):默认建设的socket都是阻塞的,非阻塞IO要求socket被配置为NONBLOCK。留意这里所说的NIO并非Java的NIO(New IO)库。

(3)IO多路复用(IO Multiplexing):即经典的Reactor计划模式,偶然也称为异步阻塞IO,,Java中的Selector和Linux中的epoll都是这种模子。

(4)异步IO(Asynchronous IO):即经典的Proactor计划模式,也称为异步非阻塞IO。

同步和异步的观念描写的是用户线程与内核的交互方法:同步是指用户线程提倡IO哀求后必要守候可能轮询内核IO操纵完成后才气继承执行;而异步是指用户线程提倡IO哀求后仍继承执行,当内核IO操纵完成后会关照用户线程,可能挪用用户线程注册的回调函数。

阻塞和非阻塞的观念描写的是用户线程挪用内核IO操纵的方法:阻塞是指IO操纵必要彻底完成后才返回到用户空间;而非阻塞是指IO操纵被挪用后当即返回给用户一个状态值,无需比及IO操纵彻底完成。

其它,Richard Stevens 在《Unix 收集编程》卷1中提到的基于信号驱动的IO(Signal Driven IO)模子,因为该模子并不常用,本文不作涉及。接下来,我们具体说明四种常见的IO模子的实现道理。为了利便描写,我们同一行使IO的读操纵作为示例。

一、同步阻塞IO

同步阻塞IO模子是最简朴的IO模子,用户线程在内核举办IO操纵时被阻塞。

如图1所示,用户线程通过体系挪用read提倡IO读操纵,由用户空间转到内核空间。内核比及数据包达到后,然后将吸取的数据拷贝到用户空间,完成read操纵。

用户线程行使同步阻塞IO模子的伪代码描写为:

{

read(socket, buffer);

process(buffer);

}

即用户必要守候read将socket中的数据读取到buffer后,才继承处理赏罚吸取的数据。整个IO哀求的进程中,用户线程是被阻塞的,这导致用户在提倡IO哀求时,不能做任何工作,对CPU的资源操作率不足。

二、同步非阻塞IO

同步非阻塞IO是在同步阻塞IO的基本上,将socket配置为NONBLOCK。这样做用户线程可以在提倡IO哀求后可以当即返回。

如图2所示,因为socket长短阻塞的方法,因此用户线程提倡IO哀求时当即返回。但并未读取到任何数据,用户线程必要不绝地提倡IO哀求,直到数据达到后,才真正读取到数据,继承执行。

用户线程行使同步非阻塞IO模子的伪代码描写为:

{

while(read(socket, buffer) != SUCCESS)

;

process(buffer);

}

即用户必要不绝地挪用read,实行读取socket中的数据,直到读取乐成后,才继承处理赏罚吸取的数据。整个IO哀求的进程中,固然用户线程每次提倡IO哀求后可以当即返回,可是为了比及数据,仍必要不绝地轮询、一再哀求,耗损了大量的CPU的资源。一样平常很少直接行使这种模子,而是在其他IO模子中行使非阻塞IO这一特征。

三、IO多路复用

IO多路复用模子是成立在内核提供的多路疏散函数select基本之上的,行使select函数可以停止同步非阻塞IO模子中轮询守候的题目。

如图3所示,用户起首将必要举办IO操纵的socket添加到select中,然后阻塞守候select体系挪用返回。当数据达到时,socket被激活,select函数返回。用户线程正式提倡read哀求,读取数据并继承执行。

从流程上来看,行使select函数举办IO哀求和同步阻塞模子没有太大的区别,乃至还多了添加监督socket,以及挪用select函数的特殊操纵,服从更差。可是,行使select往后最大的上风是用户可以在一个线程内同时处理赏罚多个socket的IO哀求。用户可以注册多个socket,然后不绝地挪用select读取被激活的socket,即可到达在统一个线程内同时处理赏罚多个IO哀求的目标。而在同步阻塞模子中,必需通过多线程的方法才气到达这个目标。

用户线程行使select函数的伪代码描写为:

{

select(socket);

while(1) {

sockets = select();

for(socket in sockets) {

if(can_read(socket)) {

read(socket, buffer);

process(buffer);

}

}

}

}

个中while轮回前将socket添加到select监督中,然后在while内一向挪用select获取被激活的socket,一旦socket可读,便挪用read函数将socket中的数据读取出来。

然而,行使select函数的利益并不只限于此。固然上述方法应承单线程内处理赏罚多个IO哀求,可是每个IO哀求的进程照旧阻塞的(在select函数上阻塞),均匀时刻乃至比同步阻塞IO模子还要长。假如用户线程只注书籍身感乐趣的socket可能IO哀求,然后去做本身的工作,比及数据到来时再举办处理赏罚,则可以进步CPU的操作率。

IO多路复用模子行使了Reactor计划模式实现了这一机制。

如图4所示,EventHandler抽象类暗示IO变乱处理赏罚器,它拥有IO文件句柄Handle(通过get_handle获取),以及对Handle的操纵handle_event(读/写等)。担任于EventHandler的子类可以对变乱处理赏罚器的举动举办定制。Reactor类用于打点EventHandler(注册、删除等),并行使handle_events实现变乱轮回,不绝挪用同步变乱多路疏散器(一样平常是内核)的多路疏散函数select,只要某个文件句柄被激活(可读/写等),select就返回(阻塞),handle_events就会挪用与文件句柄关联的变乱处理赏罚器的handle_event举办相干操纵。