[转]关于Blocking IO, Non-Blocking IO 和 Asynchronous I/O的理解

---恢复内容开始---html

关于Blocking IO, Non-Blocking IO 和 Asynchronous I/O的理解

归纳来讲,一个IO操做能够分为两个部分:发出请求、结果完成。若是从发出请求到结果返回,一直Block,那就是Blocking IO;若是发出请求就能够返回(结果完成不考虑),就是non-blocking IO;若是发出请求就返回,结果返回是Block在select或者poll上的,则其只能称为IO multiplexing;若是发出请求就返回,结果返回经过Call Back的方式被处理,就是AIO。java

文[2]中图画的不错,说的也比较清楚借来用一下。windows

 

Blocking IO设计模式

这个最好理解了,在Blocking IO模式下,函数调用只有在操做完成后才会返回。下图是它调用过程的图示:服务器

 

重点解释下上图,下面例子都会讲到。首先application调用 recvfrom()转入kernel,注意kernel有2个过程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此过程一直是阻塞的。数据结构

 

Non-Blocking IO app

Non-Blocking 是Blocking的反,也就是说,即便操做没有完成,函数也能够返回。调用过程以下:异步

 

能够看见,若是直接操做它,那就是个轮询。。直到内核缓冲区有数据async

AIO也是这样啊?对!这是Non-Blocking IO 和AIO的共同点。其实从概念层面来讲Non-Blocking IO 就是AIO,他们没有什么区别。可是Non-Blocking IO是对文件描述符(*nix)或者Handle(Windows)的设置,在执行操做时不须要特殊的数据结构。Non-Blocking IO提交请求后只能经过提交的操做函数来查询操做是否完成,这是一个很大的限制。而AIO每每会提供多种通知或者查询机制,也就是说用Non-Blocking IO时只能轮询,而AIO有更多选择。因此是否支持轮询外的其余机制是AIO和Non-Blocking IO的区别。ide

Non-Blocking IO和Blocking IO的区别仅仅在操做是否可以马上完成,若是可以马上完成,IO函数的行为是同样的;若是不能马上完成,Non-Blocking IO会返回EAGAIN或者EWOULDBLOCK,而Blocking IO会一直阻塞。

I/O multiplexing (select and poll)
最多见的I/O复用模型,select。

 

select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,可是select能处理多个套接字。

signal driven I/O (SIGIO)
只有UNIX系统支持,感兴趣的课查阅相关资料

 

I/O multiplexing (select and poll)相比,它的优点是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。

 

Asynchronous I/O (the POSIX aio_functions)

不多有*nix系统支持,windows的IOCP则是此模型。

The POSIX asynchronous I/O (AIO) interface allows applications to initiate one or more I/O operations that are performed asynchronously (i.e., in the background). The application can elect to be notified of completion of the I/O operation in a variety of ways: by delivery of a signal, by instantiation of a thread, or no notification at all.

AIO让应用发起一个操做请求,让这个请求被异步地执行。应用能够选择在操做完成时被通知到或者不被通知。因此通知机制并非AIO的核心,可是须要提供几种选择。在Windows上,Overlapped IO是AIO的实现,IOCP在Overlapped IO的基础上提供了高效的通知机制。

 

 

彻底异步的I/O复用机制,由于纵观上面其它四种模型,至少都会在由kernel copy data to application时阻塞。而该模型是当copy完成后才通知application,可见是纯异步的。好像只有windows的完成端口是这个模型,效率也很出色。

下面是以上五种模型的比较


 

能够看出,越日后,阻塞越少,理论上效率也是最优。

 

下面能够把select,epoll,iocp,kqueue按号入座。

select和iocp分别对应第3种与第5种模型,那么epoll与kqueue呢?其实也于select属于同一种模型,只是更高级一些,能够看做有了第4种模型的某些特性,如callback机制。

那么,为何epoll,kqueue比select高级? 

答案是,他们无轮询。由于他们用callback取代了。想一想看,当套接字比较多的时候,每次select()都要经过遍历FD_SETSIZE个Socket来完成调度,无论哪一个Socket是活跃的,都遍历一遍。这会浪费不少CPU时间。若是能给套接字注册某个回调函数,当他们活跃时,自动完成相关操做,那就避免了轮询,这正是epoll与kqueue作的。

windows or *nix (IOCP or kqueue/epoll)?

诚然,Windows的IOCP很是出色,目前不多有支持asynchronous I/O的系统,可是因为其系统自己的局限性,大型服务器仍是在UNIX下。并且正如上面所述,kqueue/epoll 与 IOCP相比,就是多了一层从内核copy数据到应用层的阻塞,从而不能算做asynchronous I/O类。可是,这层小小的阻塞无足轻重,kqueue与epoll已经作得很优秀了。

提供一致的接口,IO Design Patterns

实际上,不论是哪一种模型,均可以抽象一层出来,提供一致的接口,广为人知的有ACE,Libevent这些,他们都是跨平台的,并且他们自动选择最优的I/O复用机制,用户只需调用接口便可。说到这里又得说说2个设计模式,Reactor and Proactor。有一篇经典文章http://www.artima.com/articles/io_design_patterns.html值得阅读,Libevent是Reactor模型,ACE提供Proactor模型。实际都是对各类I/O复用机制的封装。

Java nio包是什么I/O机制?

我曾天真的认为java nio封装的是IOCP。。如今能够肯定,目前的java本质是select()模型,能够检查/jre/bin/nio.dll得知。至于java服务器为何效率还不错。。我也不得而知,多是设计得比较好吧。。-_-。

=====================分割线==================================

总结一些重点:

只有IOCP是asynchronous I/O,其余机制或多或少都会有一点阻塞。 select低效是由于每次它都须要轮询。但低效也是相对的,视状况而定,也可经过良好的设计改善 epoll, kqueue是Reacor模式,IOCP是Proactor模式。 java nio包是select模型。。

 

Reference:

1. http://www.artima.com/articles/io_design_patterns.html

2. http://hi.baidu.com/ailuoli/blog/item/f9fe370f0dee7bf1ab6457e7.html

 
 

---恢复内容结束---

关于Blocking IO, Non-Blocking IO 和 Asynchronous I/O的理解

归纳来讲,一个IO操做能够分为两个部分:发出请求、结果完成。若是从发出请求到结果返回,一直Block,那就是Blocking IO;若是发出请求就能够返回(结果完成不考虑),就是non-blocking IO;若是发出请求就返回,结果返回是Block在select或者poll上的,则其只能称为IO multiplexing;若是发出请求就返回,结果返回经过Call Back的方式被处理,就是AIO。

文[2]中图画的不错,说的也比较清楚借来用一下。

 

Blocking IO

这个最好理解了,在Blocking IO模式下,函数调用只有在操做完成后才会返回。下图是它调用过程的图示:

 

重点解释下上图,下面例子都会讲到。首先application调用 recvfrom()转入kernel,注意kernel有2个过程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此过程一直是阻塞的。

 

Non-Blocking IO

Non-Blocking 是Blocking的反,也就是说,即便操做没有完成,函数也能够返回。调用过程以下:

 

能够看见,若是直接操做它,那就是个轮询。。直到内核缓冲区有数据

AIO也是这样啊?对!这是Non-Blocking IO 和AIO的共同点。其实从概念层面来讲Non-Blocking IO 就是AIO,他们没有什么区别。可是Non-Blocking IO是对文件描述符(*nix)或者Handle(Windows)的设置,在执行操做时不须要特殊的数据结构。Non-Blocking IO提交请求后只能经过提交的操做函数来查询操做是否完成,这是一个很大的限制。而AIO每每会提供多种通知或者查询机制,也就是说用Non-Blocking IO时只能轮询,而AIO有更多选择。因此是否支持轮询外的其余机制是AIO和Non-Blocking IO的区别。

Non-Blocking IO和Blocking IO的区别仅仅在操做是否可以马上完成,若是可以马上完成,IO函数的行为是同样的;若是不能马上完成,Non-Blocking IO会返回EAGAIN或者EWOULDBLOCK,而Blocking IO会一直阻塞。

I/O multiplexing (select and poll)
最多见的I/O复用模型,select。

 

select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,可是select能处理多个套接字。

signal driven I/O (SIGIO)
只有UNIX系统支持,感兴趣的课查阅相关资料

 

I/O multiplexing (select and poll)相比,它的优点是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。

 

Asynchronous I/O (the POSIX aio_functions)

不多有*nix系统支持,windows的IOCP则是此模型。

The POSIX asynchronous I/O (AIO) interface allows applications to initiate one or more I/O operations that are performed asynchronously (i.e., in the background). The application can elect to be notified of completion of the I/O operation in a variety of ways: by delivery of a signal, by instantiation of a thread, or no notification at all.

AIO让应用发起一个操做请求,让这个请求被异步地执行。应用能够选择在操做完成时被通知到或者不被通知。因此通知机制并非AIO的核心,可是须要提供几种选择。在Windows上,Overlapped IO是AIO的实现,IOCP在Overlapped IO的基础上提供了高效的通知机制。

 

 

彻底异步的I/O复用机制,由于纵观上面其它四种模型,至少都会在由kernel copy data to application时阻塞。而该模型是当copy完成后才通知application,可见是纯异步的。好像只有windows的完成端口是这个模型,效率也很出色。

下面是以上五种模型的比较


 

能够看出,越日后,阻塞越少,理论上效率也是最优。

 

下面能够把select,epoll,iocp,kqueue按号入座。

select和iocp分别对应第3种与第5种模型,那么epoll与kqueue呢?其实也于select属于同一种模型,只是更高级一些,能够看做有了第4种模型的某些特性,如callback机制。

那么,为何epoll,kqueue比select高级? 

答案是,他们无轮询。由于他们用callback取代了。想一想看,当套接字比较多的时候,每次select()都要经过遍历FD_SETSIZE个Socket来完成调度,无论哪一个Socket是活跃的,都遍历一遍。这会浪费不少CPU时间。若是能给套接字注册某个回调函数,当他们活跃时,自动完成相关操做,那就避免了轮询,这正是epoll与kqueue作的。

windows or *nix (IOCP or kqueue/epoll)?

诚然,Windows的IOCP很是出色,目前不多有支持asynchronous I/O的系统,可是因为其系统自己的局限性,大型服务器仍是在UNIX下。并且正如上面所述,kqueue/epoll 与 IOCP相比,就是多了一层从内核copy数据到应用层的阻塞,从而不能算做asynchronous I/O类。可是,这层小小的阻塞无足轻重,kqueue与epoll已经作得很优秀了。

提供一致的接口,IO Design Patterns

实际上,不论是哪一种模型,均可以抽象一层出来,提供一致的接口,广为人知的有ACE,Libevent这些,他们都是跨平台的,并且他们自动选择最优的I/O复用机制,用户只需调用接口便可。说到这里又得说说2个设计模式,Reactor and Proactor。有一篇经典文章http://www.artima.com/articles/io_design_patterns.html值得阅读,Libevent是Reactor模型,ACE提供Proactor模型。实际都是对各类I/O复用机制的封装。

Java nio包是什么I/O机制?

我曾天真的认为java nio封装的是IOCP。。如今能够肯定,目前的java本质是select()模型,能够检查/jre/bin/nio.dll得知。至于java服务器为何效率还不错。。我也不得而知,多是设计得比较好吧。。-_-。

=====================分割线==================================

总结一些重点:

只有IOCP是asynchronous I/O,其余机制或多或少都会有一点阻塞。 select低效是由于每次它都须要轮询。但低效也是相对的,视状况而定,也可经过良好的设计改善 epoll, kqueue是Reacor模式,IOCP是Proactor模式。 java nio包是select模型。。

 

Reference:

1. http://www.artima.com/articles/io_design_patterns.html

2. http://hi.baidu.com/ailuoli/blog/item/f9fe370f0dee7bf1ab6457e7.html

相关文章
相关标签/搜索