前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BIO到NIO的升级演练

BIO到NIO的升级演练

作者头像
黑洞代码
发布2021-01-14 15:33:33
4710
发布2021-01-14 15:33:33
举报

IO通信即消息的输入、输出,这涉及到应用、操作系统以及硬件之间的通信,在java中,这涉及到用户态、内核态以及硬件的操作。在jdk1.4之前,IO(统称BIO)通信在Java语言中,性能一直堪忧,基于此,在jdk1.4开始,NIO面世了,并以高性能而闻名,并以此为基础,做了许多结构优化。

一、Java IO 模型

1、同步 VS 异步

同步:每个请求必须逐个的被处理,在上一个请求未执行完之前,下一个请求无法执行。是一种串行的处理模式。在Java语言中,用户线程发起IO操作,必须等待内核IO处理完之后,用户线程才能继续后续工作。

异步:多个请求可以并行工作,每个请求的工作都相对是独立的,不会相互作用。在Java语言中,用户线程发起IO操作,不用等待内核IO的操作,可以直接处理后续工作,等内核IO处理完后,后通知用户线程。例如:线程回调的方式。

2、阻塞 VS 非阻塞

阻塞:某个请求发出后,如果请求需要的条件无法得到满足,则后一直处于等待状态。

非阻塞:某个请求发出后,如果请求需要的资源无法得到满足,也会立即收到结果,告知不满足,不会一直处于等待状态,后面可以通过轮询的方式来判断请求需要的条件是否已经可以满足,并能获取最终结果。

PS:阻塞不等于同步,非阻塞不等于异步,因为侧重点不同。阻塞/非阻塞的侧重点是,请求是否立刻返回,即使返回的是条件不足。而同步/异步的侧重点是,多个请求时,后发的请求是否必须等待先发的请求完成,才能进行后续处理。

2、BIO

BIO就是同步阻塞的IO操作。下图是BIO在进行IO操作时,数据流向过程。

User Space是用户态空间,Kernel Space是内核态空间,Disk是硬盘。

在读取硬盘文件时,首先文件数据是从Disk复制到Kernel Space的buffer,再从Kernel Space的buffer复制到User Space的buffer,最后Java代码操作的是User Space的buffer。

总结:通过BIO,读取硬盘的文件数据,要经历两次复制的操作,才能把数据读取到内存空间。

3、NIO

NIO是同步非阻塞的IO操作。下图是NIO在进行IO操作时,数据流向过程。

User Space是用户态空间,Kernel Space是内核态空间,Disk是硬盘。

在读取硬盘文件时,首先文件数据是从Disk复制到Kernel Space的buffer,该buffer的地址会映射到Physical memory(Direct Memory)中(可以自行查阅内存映射缓冲区),Java代码通过地址映射能直接读取到Kernel Space的buffer中数据。

总结:通过NIO,读取硬盘的文件数据,最多经历一次复制,就能把数据读取到内存中。

4、BIO/NIO文件拷贝测试

在本地同时拷贝一份400M的mp4资源,BIO跟NIO所消耗的时间比较。

代码语言:javascript
复制
public  static  void main(String[] args) throws Exception {
    String sourcePath = "/Users/Desktop/IO.mp4";
    String bioTarget = "/Users/Desktop//IO.bio.mp4";
    String nioTarge = "/Users/Desktop/mytest/课件/IO/IO.nio.mp4";
    long t1 = System.currentTimeMillis();
    bioCopy(sourcePath, bioTarget);
    long t2 = System.currentTimeMillis();
    System.out.println("BIO实现文件拷贝耗时:" + (t2-t1) + "ms");
    nioCopy(sourcePath, nioTarge);
    long t3 = System.currentTimeMillis();
    System.out.println("NIO实现文件拷贝耗时:" + (t3-t2) + "ms");
}

private  static  void bioCopy(String sourcePath, String destPath) throws Exception{
    File source = new File(sourcePath);
    File dest = new File(destPath);
    if(!dest.exists()) {
        dest.createNewFile();
    }
    FileInputStream fis = new FileInputStream(source);
    FileOutputStream fos = new FileOutputStream(dest);
    byte [] buf = new byte [1024];
    int len = 0;
    while((len = fis.read(buf)) != -1) {
        fos.write(buf, 0, len);
    }
    fis.close();
    fos.close();
}

private  static  void nioCopy(String sourcePath, String destPath) throws Exception{
    File source = new File(sourcePath);
    File dest = new File(destPath);
    if(!dest.exists()) {
        dest.createNewFile();
    }
    FileInputStream fis = new FileInputStream(source);
    FileOutputStream fos = new FileOutputStream(dest);
    FileChannel sourceCh = fis.getChannel();
    FileChannel destCh = fos.getChannel();
    destCh.transferFrom(sourceCh, 0, sourceCh.size());
    sourceCh.close();
    destCh.close();
}

5、IO在tomcat中优化。

在tomcat7以及之前,tomcat默认都是以BIO的方式进行启动的,在tomcat8开始,都是默认以NIO的方式开始进行启动。

下图是tomcat/config/server.xml中关于8080的配置。

tomcat7跟tomcat8的配置是一样的,但是在启动日志里面,会看出不一样的情况,请看下图:

tomcat7的启动日志:能清晰的看到bio字眼

tomcat8的启动日志:能清晰的看到nio字眼

tomcat7跟tomcat8在server.xml中关于8080的配置是一样的,但是启动日志不一样,在这里说明tomcat用nio的方式比用bio的方式,性能更加的强大。下面是作者用jmeter给予bio/nio做的压测。

以800线程做的测试:

以1000线程做的测试:

以1200线程做的测试:

因为考虑的不确定的因素可能会对测试结果造成影响,所以作者特地测试了三次,从结果来看,在tomcat中,使用nio后的性能确实比bio的性能好。

6、NIO在Redis中使用。

百度:Redis是单线程,还是多线程

得到的结论是:Redis是单线程的。

那既然Redis是单线程的,为什么确是高并发优化中必不可少的一个组件呢?还能支撑几万的QPS呢。

之所以说Redis是单线程的,是因为Redis是用单线程来处理所有的客户端request请求。但Redis的后台任务,还是多线程的模式在进行的。单线程就能处于所有的客户端request请求,是基于一种epoll模型进行工作的。epoll的伪代码如下:

从结构上看,等同于Java NIO中的Selector。

下面演示NIO在socket.io通信中优化。

客户端code:

将hello做延迟发送,一次发送一次字符。

客户端时间消耗:

BIO服务端code:

NIO服务端code:

总结:

客户端,因为发送数据做了延迟操作,所消耗的时间都是6000ms。

BIO服务端,从接收客户端消息到接收完,每条都要耗时6000ms。

NIO服务端,从接收客户端消息到接收完,每条耗时只要几毫秒。

对于客户端来说,时间性能上没有提升。但是对于服务端来说,使用NIO比BIO在时间性能上提高了几千倍。

所以:BIO是阻塞的,而NIO是非阻塞的。NIO可以在BIO阻塞的时间上去处理别的操作,从而提高服务端性能。

7、IO模型图

BIO模型图:

NIO模型图:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 落叶飞翔的蜗牛 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档