BIO到NIO的演变过程
时间:2022-07-23
本文章向大家介绍BIO到NIO的演变过程,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
背景
学习任何东西之前都得知道他是为什么而产生的。任何一个设计,或技术。都是为了解决某个或多个问题而产生的。即BIO到NIO到多路复用再到epollo 再到netty网络编程框架。今天我们来看看这个演进的过程。
IO的演进
下图是来自培训机构的一个大佬的图:
什么是IO?
- 我自己的理解:从本地磁盘或者网络传输过来的数据的读取和写入的过程。也就是从网卡或者磁盘的数据到应用程序内部(JVM的动态内存中)的过程。这个过程是相当耗费时间的,看看下面的数据。随机访问相差10万倍。在性价比的驱动下,优化硬件的成本远远比优化软件这方面的成本高的时候或者还有其他原因的时候那么就去优化一下我们的访问方式。
1.顺序访问:这种情况下,内存访问速度仅仅是硬盘访问速度的6~7倍(358.2M / 53.2M = 6.7)
2.随机访问:这种情况下,内存访问速度就要比硬盘访问速度快上10万倍以上 (36.7M / 316 = 113,924)
在看各个IO之前先理解一下这个过程linux是如何实现的: 在linux系统中一切皆文件。在 系统中启动一个服务的时候,我们会为其定义端口号代表这个服务,启动成功后linux就会创建一个监听,每接入一个clinet就会被我们的服务监听到,然后去内核拿这个数据。 重要的就是图中的fd(文件描述符)和内核交互的过程中就是根据linux系统中的这个文件描述符来确定是那个客户端的。
1.BIO
- BIO也就是阻塞IO的意思,这里的阻塞是指的应用程序监听到服务器有端口连接进来,在与内核进行交互的时候是阻塞的。看下面的图理解一下:
如图上红色线的部分。我们监听到有个client进来的时候,于是我们起一个线程去请求是否有数据进来,此时这个阶段是阻塞的,没有数据返回就会一直等待。当又有新的客户端进来的时候我们只能再起新的进程了。那就使用多线程的方式再起新的线程去请求。
- 毫无疑问,这是有问题的,我们都知道创建一个线程会耗费内存的。所以创建多个线程有可能会产生OOM的。
- 有人就说了我们起一个线程池,搞一个没有核心线程数的线程池。只有最大线程数,然后设置过期时间,是个解决办法。但是不合理。同时涌入上万甚至更多得用户,肯定得蹦
- 那搞一个非阻塞的线程呗。 在JDK1.4 NIO登场。
2.NIO
- 从上文中可知,NIO解决的问题之一是不让创建多个线程。那NIO的设计这给出的办法就是让和内核交互的这个过程中是非阻塞的。不管他有没有数据进来请求后就会返回。 2. 但是得一直轮训接入的客户端的文件描述符,查看是否有数据进来。看下图品一下:
- 从上面可以看出,解决了之前必须创建多个线程的问题。现在我们再看看在这个模型下会又有什么问题呢?for循环便利那岂不是很耗费CPU资源啊,当我们有N多个客户端进来给你CPU打满,那其他的client也不就是死。所以这又出现问题了。
- 于是又有大佬站出来了,提出了IO的多路复用原则。
3. NIO+多路复用
- 由于在NIO中是非阻塞的,现在主要问题是我们并不知道哪些客户端会有数据过来,我们得遍历所有客户端的来查看是否有数据,那就是我们如何才能让服务程序能知道哪些客户端有数据了,需要去读取。大佬在内核实现了selector,epoll ,reactor等多路复用的线程模型。其中的思想就是可以通过他们提供的方法可以拿出就绪有数据过来的客户端fd。
总结
大概是过了一下从BIO到NIO+IO多路复用的演进(IO模型的演进)
- BIO 遇到创建多个线程有可能导致OOM,对系统的并发能力有极大限制
- NIO,导致CPU空转的,导致CPU做无用功。
- NIO+多路复用以及已有实现的NIO+多路复用的模型
思考,selector和epoll是如何实现可以知道有客户端的数据进来了,且通知应用服务去读区数据呢?
资源:
- JavaNIO的具体实现 :https://juejin.im/entry/599f971af265da247d728531
- 本文参考视频:https://www.bilibili.com/video/BV1cT4y1g79r?from=search&seid=2733076814654841327
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- HW|蓝队实战溯源反制手册分享
- 工具开发|Burp插件Unexpected_information
- 爱了!安利一个相见恨晚的可视化学习网站
- pandas+PyQt5轻松制作数据处理工具
- Python高效编程之88条军规(1):编码规范、字节序列与字符串
- 这是一份 pip 常用命令小结~
- 太震撼了,我用python画出全北京的公交线路动图
- 小伙Python爬虫并自制新闻网站,太好玩了
- TRTC Android端开发接入学习之视频会议(八)
- MySQL锁都分不清,怎么面试进大厂?
- Kubernetes Controller高可用诡异的15mins超时
- 这几项超好用的云开发扩展能力,别说你还不知道!
- Ubuntu上一键卸载安装mysql脚本
- Python-批量修改图片全部颜色,批量修改图片的指定颜色,马甲包一键换主题UI
- 【SpringBoot DB 系列】h2databse 集成示例 demo