简介
IO模型是网络编程中十分重要,却也是容易搞混的部分,一般IO模型都从两个角度来划分,分别是同步异步以及阻塞非阻塞,有同步阻塞IO、异步非阻塞。同步还是异步取决于消息通知的机制,而阻塞还是非阻塞取决于线程状态是否挂起
Linux IO模型
- 同步阻塞(BIO)
用户进程调用了recv系统调用后,从内核准备数据到准备好从内核空间复制到用户空间整个期间用户进程都是阻塞的 - 同步非阻塞(NIO)
用户进程调用read操作,如果数据没有准备好则返回错误码,数据准备好返回准备好信号,所以在数据准备好之前用户进程需要轮询内核状态,但是这期间不是阻塞的,直到内核数据准备好之后,用户进程调用recvfrom系统调用将数据从内核复制到用户空间,当然数据复制的过程仍然是阻塞的 - IO 多路复用
同步非阻塞的方式不断的轮询,十分浪费cpu,一个socket还好如果太多则完全顶不住,所以引入了单线程可以轮询多个socket的状态,其中任何一个socket数据准备好,系统调用就返回(select、poll、epoll),这时才进行io操作调用recvfrom。select与epoll的区别在于select轮询n个socket的状态时间复杂度为o(n),而epoll实现了当某个socket有事件发生后会通知用户进程,时间复杂度降到了o(1) - 异步非阻塞(信号驱动)
用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,等到socket数据准备好了,内核直接复制数据给用户进程,然后从内核通知给用户进程。IO两个阶段,进程都是非阻塞的。(libevent、libev、libuv)
JDK BIO实现
jdk的bio使用的同步阻塞模型
JDK NIO 实现
jdk的nio使用的IO多路复用模型,在linux2.6版本之后使用的epoll,之前的是poll,在mac中使用的kqueue
JDK AIO 实现
jdk的aio使用的异步非阻塞模型,具体实现待定
Netty IO 模型
netty的io模型使用的jdk的nio实现,每个nioeventloop都会启动一个jdk的selector,每个selector底层使用的epoll实现(linux2.6之后),同时netty将io任务以及定时任务通过一个io radio的参数配置,使得同一个线程分别可以处理io以及定时的任务。
另外,netty作为服务端使用时,启动了两个线程池分别为bossgroup何workergroup,其中的每个线程就是nioeventloop实现的,bossgroup负责acceptor的工作,workergroup负责io业务处理