作者:不学无数的程序员链接:https://www.jianshu.com/p/25b328753017

压缩20M文件从30秒到1秒的优化过程

有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩成一个压缩包通过网络流传输出去。之前没有接触过用Java压缩文件的,所以就直接上网找了一个例子改了一下用了,改完以后也能使用,但是随着前端所传图片的大小越来越大的时候,耗费的时间也在急剧增加,最后测了一下压缩20M的文件竟然需要30秒的时间。压缩文件的代码如下。

这里找了一张2M大小的图片,并且循环十次进行测试。打印的结果如下,时间大概是30秒。

第一次优化过程-从30秒到2秒

进行优化首先想到的是利用缓冲区**BufferInputStream。在FileInputStreamread()**方法每次只读取一个字节。源码中也有说明。

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

BufferedInputStream内部封装了一个byte数组用于存放数据,默认大小是8192

优化过后的代码如下

输出

可以看到相比较于第一次使用FileInputStream效率已经提升了许多了

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

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

使用Channel

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

在NIO中能够产生FileChannel的有三个类。分别是FileInputStreamFileOutputStream、以及既能读又能写的RandomAccessFile

源码如下

我们可以看到这里并没有使用ByteBuffer进行数据传输,而是使用了transferTo的方法。这个方法是将两个通道进行直连。

这是源码上的描述文字,大概意思就是使用transferTo的效率比循环一个Channel读取出来然后再循环写入另一个Channel好。操作系统能够直接传输字节从文件系统缓存到目标的Channel中,而不需要实际的copy阶段。

copy阶段就是从内核空间转到用户空间的一个过程

可以看到速度相比较使用缓冲区已经有了一些的提高。

内核空间和用户空间

那么为什么从内核空间转向用户空间这段过程会慢呢?首先我们需了解的是什么是内核空间和用户空间。在常用的操作系统中为了保护系统中的核心资源,于是将系统设计为四个区域,越往里权限越大,所以Ring0被称之为内核空间,用来访问一些关键性的资源。Ring3被称之为用户空间。

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

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

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

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

非直接缓冲区:非直接缓冲区就是我们上面所讲内核态作为中间人,每次都需要内核在中间作为中转。

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

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

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

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

使用内存映射文件

NIO中新出的另一个特性就是内存映射文件,内存映射文件为什么速度快呢?其实原因和上面所讲的一样,也是在内存中开辟了一段直接缓冲区。与数据直接作交互。源码如下

打印如下

可以看到速度和使用Channel的速度差不多的。

使用Pipe

Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。其中source通道用于读取数据,sink通道用于写入数据。可以看到源码中的介绍,大概意思就是写入线程会阻塞至有读线程从通道中读取数据。如果没有数据可读,读线程也会阻塞至写线程写入数据。直至通道关闭。

Whether or not a thread writing bytes to a pipe will block until another thread reads those bytes

我想要的效果是这样的。源码如下:

源码地址https://github.com/modouxiansheng/Doraemon

总结

生活处处都需要学习,有时候只是一个简单的优化,可以让你深入学习到各种不同的知识。所以在学习中要不求甚解,不仅要知道这个知识也要了解为什么要这么做。

fileinputstream resources 读取文件_压缩20M文件从30秒到1秒,包教包会相关推荐

  1. fileinputstream读取文件_压缩 20M 文件从 30 秒到 1 秒的优化过程

    <阿里云双十一活动,云服务器每月最低仅需7元> 来源:jianshu.com/p/25b328753017 第一次优化过程-从30秒到2秒 第二次优化过程-从2秒到1秒 使用频道 使用内存 ...

  2. 压缩 20M 文件从 30 秒到 1 秒的优化过程!

    目录 第一次优化过程-从30秒到2秒 第二次优化过程-从2秒到1秒 使用Channel 使用内存映射文件 使用Pipe 总结 参考文章 有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩 ...

  3. 压缩20M文件从30秒到1秒的优化过程

    有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩成一个压缩包通过网络流传输出去.之前没有接触过用Java压缩文件的,所以就直接上网找了一个例子改了一下用了,改完以后也能使用,但是随着前 ...

  4. Java 压缩20M文件从30秒到1秒的优化过程,真不相信?

    (源码下载方式在文末) 有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩成一个压缩包通过网络流传输出去.之前没有接触过用Java压缩文件的,所以就直接上网找了一个例子改了一下用了,改完 ...

  5. Java压缩20M文件非常厉害

    有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩成一个压缩包通过网络流传输出去.之前没有接触过用Java压缩文件的,所以就直接上网找了一个例子改了一下用了,改完以后也能使用,但是随着前 ...

  6. pydicom读取头文件_.dcm格式文件软件读取及python处理详解

    要处理一些.dcm格式的焊接缺陷图像,需要读取和显示.dcm格式的图像.通过搜集资料收集到一些医学影像,并通过pydicom模块查看.dcm格式文件. 若要查看dcm格式文件,可下echo viewe ...

  7. python输入文件名读取文件_[Python] python3 文件操作:从键盘输入、打开关闭文件、读取写入文件、重命名与删除文件等...

    1.从键盘输入 Python 2有两个内置的函数用于从标准输入读取数据,默认情况下来自键盘.这两个函数分别是:input()和raw_input(). Python 3中,不建议使用raw_input ...

  8. C 怎么读取Cpp文件_从PCD文件写入和读取点云数据

    (1)学习向PCD文件写入点云数据 建立工程文件ch2,然后新建write_pcd.cpp CMakeLists.txt两个文件 write_pcd.cpp : #include <iostre ...

  9. arcgis怎么压缩tif文件_微信传文件有大小限制怎么办?教你3秒把100MPPT压缩成10M...

    现在用微信来办公的人越来越多了,不过大家都知道,微信传文件的时候有点小麻烦,文件的大小有限制,电脑版最大只能传25M的文件,一些比较大的文件,像PPT,一般都几十M,大的几百M都有,无法通过微信传输, ...

最新文章

  1. Oracle数据库基础入门《二》Oracle内存结构
  2. python利器怎么用-bluepy 一款python封装的BLE利器简单介绍
  3. JS循环绑定对象或变量
  4. 深入浅出: Java回调机制(异步)
  5. 从产品角度聊一聊疯狂猜图为何这么火
  6. Windows API的时间结构体、时间转换及时间获取
  7. 论文浅尝 - AAAI2020 | 多轮对话系统中的历史自适应知识融合机制
  8. 英特尔核芯显卡控制面板没有了_核显和独显、集成显卡有什么区别
  9. LCA+tarjan
  10. JS拖动技术--- 关于setCapture
  11. 比特币 POW 白皮书 区块篡改成功的概率计算详解
  12. angular自带的一些api_在Angular软件中执行API请求的正确方式,了解一下
  13. 协同过滤算法:在线推荐系统如何工作?
  14. 数控加工中心编程和UG编程和什么区别
  15. 关于分布式服务中的中间件技术入门概述
  16. 实验吧-PHP大法-eregi()函数
  17. 精读《图解密码技术》--第一章 环游密码世界
  18. 《2018区块链技术应用白皮书》完整版查看
  19. python 证书-python requests证书问题解决
  20. Dataview产品

热门文章

  1. html如何获得网址,已知一个网址,如何获得该网址对应的html源代码?在del 找人事管理软件...
  2. 安卓 无权限 访问_U盘提示无权限访问怎么办 电脑U盘访问权限管理
  3. 在python函数中参数分类的详细教程
  4. python基础教程:排列与组合
  5. Python基础教程:属性值设置和判断变量是否存在
  6. 13道Python3实例
  7. Python回调函数用法实例
  8. php 多维数组按值排序,按子值对php多维数组排序
  9. 虚拟机 Linux ubuntu16.04 对 windows 设置共享文件夹教程(samba)(ubuntu16.04换源【更换下载源】【更换源】【更新源】)(如果连不上需要开SSH服务)
  10. flask html css文件更改后(谷歌)浏览器不及时更新样式文件怎么办?(ctrl+shift+delete清除缓存的图片和文件)