加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_开封站长网 (http://www.0378zz.com/)- 科技、AI行业应用、媒体智能、低代码、办公协同!
当前位置: 首页 > 站长资讯 > 评论 > 正文

从30秒到1秒的优化过程

发布时间:2021-04-22 10:07:11 所属栏目:评论 来源:互联网
导读:调用本地方法与原生操作系统进行交互,从磁盘中读取数据。每读取一个字节的数据就调用一次本地方法与操作系统交互,是非常耗时的。例如我们现在有30000个字节的数据,如果使用FileInputStream那么就需要调用30000次的本地方法来获取这些数据,而如果使用缓冲

调用本地方法与原生操作系统进行交互,从磁盘中读取数据。每读取一个字节的数据就调用一次本地方法与操作系统交互,是非常耗时的。例如我们现在有30000个字节的数据,如果使用FileInputStream那么就需要调用30000次的本地方法来获取这些数据,而如果使用缓冲区的话(这里假设初始的缓冲区大小足够放下30000字节的数据)那么只需要调用一次就行。因为缓冲区在第一次调用read()方法的时候会直接从磁盘中将数据直接读取到内存中。随后再一个字节一个字节的慢慢返回。

> BufferedInputStream内部封装了一个byte数组用于存放数据,默认大小是81看到相比较于第一次使用FileInputStream效率已经提升了许多了。

第二次优化过程-从2秒到1秒

使用缓冲区buffer的话已经是满足了我的需求了,但是秉着学以致用的想法,就想着用NIO中知识进行优化一下。

使用Channel

为什么要用Channel呢?因为在NIO中新出了Channel和ByteBuffer。正是因为它们的结构更加符合操作系统执行I/O的方式,所以其速度相比较于传统IO而言速度有了显著的提高。Channel就像一个包含着煤矿的矿藏,而ByteBuffer则是派送到矿藏的卡车。也就是说我们与数据的交互都是与ByteBuffer的交互。

在NIO中能够产生FileChannel的有三个类。分别是FileInputStream、FileOutputStream、以及既能读又能写的RandomAccessFile。户空间。在常用的操作系统中为了保护系统中的核心资源,于是将系统设计为四个区域,越往里权限越大,所以Ring0被称之为内核空间,用来访问一些关键性的资源。Ring3被称之为用户空间。

> 用户态、内核态:线程处于内核空间称之为内核态,线程处于用户空间属于用户态

那么我们如果此时应用程序(应用程序是都属于用户态的)需要访问核心资源怎么办呢?那就需要调用内核中所暴露出的接口用以调用,称之为系统调用。例如此时我们应用程序需要访问磁盘上的文件。此时应用程序就会调用系统调用的接口open方法,然后内核去访问磁盘中的文件,将文件内容返回给应用程序。大致的流程如下

直接缓冲区和非直接缓冲区

既然我们要读取一个磁盘的文件,要废这么大的周折。有没有什么简单的方法能够使我们的应用直接操作磁盘文件,不需要内核进行中转呢?有,那就是建立直接缓冲区了。

  •  非直接缓冲区:非直接缓冲区就是我们上面所讲内核态作为中间人,每次都需要内核在中间作为中转。
  •  直接缓冲区:直接缓冲区不需要内核空间作为中转copy数据,而是直接在物理内存申请一块空间,这块空间映射到内核地址空间和用户地址空间,应用程序与磁盘之间数据的存取通过这块直接申请的物理内存进行交互。

既然直接缓冲区那么快,我们为什么不都用直接缓冲区呢?其实直接缓冲区有以下的缺点。直接缓冲区的缺点:

  1.  不安全
  2.  消耗更多,因为它不是在JVM中直接开辟空间。这部分内存的回收只能依赖于垃圾回收机制,垃圾什么时候回收不受我们控制。
  3.  数据写入物理内存缓冲区中,程序就丧失了对这些数据的管理,即什么时候这些数据被最终写入从磁盘只能由操作系统来决定,应用程序无法再干涉。

> 综上所述,所以我们使用transferTo方法就是直接开辟了一段直接缓冲区。所以性能相比而言提高了许多

使用内存映射文件

(编辑:开发网_开封站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读