BIO&NIO&AIO

递进过程

BIO(blocking)

a. 创建一个serverSocket,在accept新的客户端连接时会阻塞,在客户端连接成功后,read信息时也会阻塞。只能单线程处理。
b. 在每次accept到新连接时,就开启一个子线程处理。但会引发C10K,C10M问题(即有很多客户端链接,创建很多线程,造成OOM)
c. 搞个线程池来处理新连接。但系统的并发度就受限于这个线程池的数量了。

NIO(new io 或者 no-blocking)同步非阻塞

a. 在获取新连接时,在read时,都不阻塞(设置为非阻塞模式)。将accept到的每个连接放入list,单线程轮询处理这些连接。虽然不阻塞,但是如果有十万个连接,其中只有数十个有消息之类的需要处理的情况,就需要十万全轮询一遍。
b. 多路复用器,selector,将服务端,客户端的channel均注册到selector上。只关注有需要处理的channel。 同步非阻塞

AIO (asynchronized 异步io) 异步非阻塞

异步非阻塞, 由操作系统完成后回调通知服务端程序启动线程去处理, 一般适用于连接数较多且连接时间较长的应用

具体说明

  1. NIO 有三大核心组件: Channel(通道), Buffer(缓冲区),Selector(多路复用器)

    • channel 类似于流,每个 channel 对应一个 buffer缓冲区,buffer 底层就是个数组
    • channel 会注册到 selector 上,由 selector 根据 channel 读写事件的发生将其交由某个空闲的线程处理
    • NIO 的 Buffer 和 channel 都是既可以读也可以
      在这里插入图片描述
  2. NIO底层在JDK1.4版本是用linux的内核函数select()或poll()来实现,跟上面的NioServer代码类似,selector每次都会轮询所有的sockchannel看下哪个channel有读写事件,有的话就处理,没有就继续遍历。
    JDK1.5开始引入了epoll基于事件响应机制来优化NIO。

  3. NioSelectorServer中的几个核心方法:

    • Selector.open() //创建多路复用器
    • socketChannel.register() //将channel注册到多路复用器上
    • selector.select() //阻塞等待需要处理的事件发生

NIO整个调用流程就是Java调用了操作系统的内核函数来创建Socket,获取到Socket的文件描述符,再创建一个Selector
对象,对应操作系统的Epoll描述符,将获取到的Socket连接的文件描述符的事件绑定到Selector对应的Epoll文件描述符上,进行事件的异步通知,这样就实现了使用一条线程,并且不需要太多的无效的遍历,将事件处理交给了操作系统内核(操作系统中断程序实现),大大提高了效率。

Epoll几个重要函数说明:

  • int epoll_create(int size);
    创建一个epoll实例,并返回一个非负数作为文件描述符,用于对epoll接口的所有后续调用。参数size代表可能会容纳size个描述符,但size不是一个最大值,只是提示操作系统它的数量级,现在这个参数基本上已经弃用了。
  • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    使用文件描述符epfd引用的epoll实例,对目标文件描述符fd执行op操作。参数epfd表示epoll对应的文件描述符,参数fd表示socket对应的文件描述符。
  • int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
    等待文件描述符epfd上的事件。epfd是Epoll对应的文件描述符,events表示调用者所有可用事件的集合,maxevents表示最多等到多少个事件就返回,timeout是超时时间。

Redis的线程模型:
Redis就是典型的基于epoll的NIO线程模型(nginx也是),epoll实例收集所有事件(连接与读写事件),由一个服务端线程连续处理所有事件命令。
Redis底层关于epoll的源码实现在redis的src源码目录的ae_epoll.c文件里,感兴趣可以自行研究。

为什么Netty使用NIO而不是AIO?
在Linux系统上,AIO的底层实现仍使用Epoll,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层不容易深度优化,Linux上AIO还不够成熟。Netty是异步非阻塞框架,Netty在NIO上做了很多异步的封装。

同步异步与阻塞非阻塞(段子):老张用普通水壶与响水壶烧水的例子。
所谓同步异步,只是对于水壶而言。普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(即NIO中,去轮询(关注)需要处理的channel),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。立等的老张,阻塞;看电视的老张,非阻塞。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值