文章目录
1 什么是BIO?
1.1 阻塞io模型说明
当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据在一开始还没有到达。比如,还没有收到一个完整的UDP包。这个时候kernel就要等待足够的数据到来)。这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边,整个进程会被阻塞(当然,是进程自己选择的阻塞)。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
blocking IO的特点就是在IO执行的两个阶段都被block了。
1.2 阻塞io线程模型说明
-
传统bio编程中,由一个独立的accepter线程负责监听客户端的连接请求,为每一个客户端创建一个新的线程处理;
缺点:模型缺乏弹性,服务端线程数与客户端的访问数呈现1:1的关系,一旦连接变多,并发量大,性能急剧下降;
伪异步io模型:
伪异步io模型将客户端的socket请求封装成一个task,投递到后端线程池进行处理,不会导致服务器随并发访问增加而出现资源耗尽和宕机;
缺点:仅优化了线程模型,没有从根本上解决io阻塞问题,当io故障,读写操作都会发生阻塞,
阻塞队列会导致后续操作全部阻塞,无法接收新的请求
2 什么是NIO?
2.1 非阻塞io简介
当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
所以,nonblocking IO的特点是用户进程需要不断的主动询问kernel数据好了没有。
非阻塞io做了什么?
保证连接异步
—>通过多路复用器保证客户端连接不被阻塞;读写操作异步
—>不是一直等待数据,而是利用缓冲区机制,有则处理,无则不等待处理其他;线程模型优化
—>通过selector线程同时处理上万个连接;
3 什么是AIO?
3.1 I/O 多路复用( IO multiplexing)
当用户进程调用了select,那么整个进程会被block
,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
所以,I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。
这个图和blocking IO的图其实并没有太大的不同,事实上,还更差一些。因为这里需要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。但是,用select的优势在于它可以同时处理多个connection。
所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
在IO multiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。
3.2 异步 I/O(asynchronous IO)
用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
3.3 AIO
NIO2.0的异步套接字通道是真正的异步非阻塞式io,对应于unix网络编程中的事件驱动i/o.
它不需要多路复用器对注册的通道进行轮询操作就可以实现异步读写,简化了NIO的编程模型
AIO做了什么:
异步文件通道
:异步套接字通道
4 io技术比较
可以发现non-blocking IO和asynchronous IO的区别还是很明显的。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check
,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel
)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。
5 netty为什么选择NIO?而不是AIO?
我们首先来看看netty创始人trustlin对于这个问题给出的回答:
这是trustlin在2014年的github上给出的回答,原因是linux的异步aio实现仍然采用的是epoll模型,与非阻塞式io没有本质区别,但是目前netty或者linu对于epoll的实现如何,还有待进一步分析,后续研究再说明!
参考
本文参考内容
https://www.cnblogs.com/yxmx/articles/1600736.html
https://www.cnblogs.com/aspirant/p/9166944.html
https://segmentfault.com/a/1190000003063859
http://www.52im.net/thread-566-1-1.html
https://segmentfault.com/a/1190000003063859