[Java Performance] 缓冲I/O(Buffered I/O)

标签: java performance buffered | 发表时间:2014-09-26 07:08 | 作者:dm_vincent
出处:http://blog.csdn.net

缓冲I/O(Buffered I/O)

InputStream.read()以及 OutputStream.write()操作的对象是单个字节。根据它们访问的资源的不同,使用这些方法可能会相当慢。

比如在使用 FileInputStream.read()时,速度会慢的令人发指。因为每次调用都会访问操作系统的内核去拿到1个字节的数据。在现代的操作系统中,内核往往会使用缓冲I/O实现,因此这个操作还不至于每次调用时会触发一次磁盘读取操作。但是缓冲区毕竟是在内核中的,所以每次调用该方法还是意味着会发生一次昂贵的系统调用来获取到内核I/O缓冲区中的1个字节。

对于写数据也是一样的。每次调用 FileOutputStream.write()方法都会将1个自己的数据存储到内核的缓冲区中。最终当文件被关闭或者调用flush方法的时候,内核才会将缓冲区的内容写入到磁盘。

对于基于文件的二进制数据I/O(File-based Binary Data I/O),务必使用BufferedInputStream或者BufferedOutputStream对底层的文件字节流进行一次封装。

对于基于文件的字符数据I/O(File-based Character Data I/O),务必使用BufferedReader或者BufferedWriter对底层的文件字符流进行一次封装。

实际上,以上的最佳实践不仅仅只限于文件I/O,对于其它各种类型的I/O几乎都适用。比如通过Socket得到的字节流(通过 getInputStream()getOutputStream()获取),在使用它们之前,也务必使用缓冲过滤流(Buffering Filter Stream)对它们进行封装。

然而,还是有特例的。当使用ByteArrayInputStream和ByteArrayOutputStream类型时,不要对它们使用缓冲过滤流。这两种类型会在内存中设置一片区域作为缓冲区,所以在为它们设置缓冲过滤流时,相当于会让数据被拷贝两次,以ByteArrayInputStream为例:

  1. 从内核缓冲区到缓冲过滤流的缓冲区
  2. 从缓冲过滤流的缓冲区到ByteArrayInputStream

当有其它过滤流(Filtering Stream)参与进来时,是否使用缓冲过滤流就需要具体问题具体分析了。比如在一个序列化的例子中:

private void writeObject(ObjectOutputStream out) throws IOException {
    if (prices == null) {
        makePrices();
    }
    out.defaultWriteObject();
}

protected void makePrices() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(prices);
    oos.close();
}

尽管ObjectOutputStream一次只会发送一个字节到下一个Stream,但是当下一个Stream就是最终的ByteArrayOutputStream时,使用BufferedOutputStream就没有意义了。这只会增加数据的拷贝次数,从而导致性能的下降。

但是当在ByteArrayOutputStream和ObjectOutputStream之间还存在其它的过滤流,也许过滤缓冲流就能派上用场了。比如当需要使用一个压缩过滤流将字节数组进行压缩时:

private void writeObject(ObjectOutputStream out) throws IOException {
    if (prices == null) {
        makeZippedPrices();
    }
    out.defaultWriteObject();
}

protected void makeZippedPrices() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream zip = new GZIPOutputStream(baos);
    BufferedOutputStream bos = new BufferedOutputStream(zip);
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(prices);
    oos.close();
    zip.close();
}

以上在GZIPOutputStream和ObjectOutputStream之间添加了一个BufferedOutputStream,这样做能够提高性能的原因是:当GZIPOutputStream的操作对象是一块数据时的性能会高于操作对象是一个字节时。

当使用Encoder/Decoder流来转换字节数据和字符数据时,使用缓冲过滤流对它们进行封装,也能够获得更好的性能。

下表是一组在进行带有压缩的序列化/反序列化时,是否使用缓冲过滤流对最终时间的影响:

操作 序列化时间 反序列化时间
无缓冲的压缩/解压缩 60.3s 79.3s
有缓冲的压缩/解压缩 26.8s 12.7s

可见,当向GZIPOutputStream和ObjectOutputStream之间添加一个BufferedOutputStream后,性能的提升是多么地明显。

总结

  1. InputStream.read()以及 OutputStream.write()的性能比较低,因为它们只是操作了一个字节。
  2. 在对文件流,Socket流,压缩流和字符编码流进行操作时,确保使用了缓冲过滤流来封装它们。
作者:dm_vincent 发表于2014-9-25 23:08:03 原文链接
阅读:113 评论:0 查看评论

相关 [java performance buffered] 推荐:

[Java Performance] 缓冲I/O(Buffered I/O)

- - CSDN博客编程语言推荐文章
缓冲I/O(Buffered I/O). InputStream.read()以及 OutputStream.write()操作的对象是单个字节. 根据它们访问的资源的不同,使用这些方法可能会相当慢. 比如在使用 FileInputStream.read()时,速度会慢的令人发指. 因为每次调用都会访问操作系统的内核去拿到1个字节的数据.

Best Performance Practices for Hibernate 5 and Spring Boot 2 (Part 1) - DZone Java

- -
Description:If not, then is important to know that attributes can be loaded lazily, as well via Hibernate bytecode instrumentation (another approach is via subentities).

MySQL的Performance Schema库

- - 数据库 - ITeye博客
Performance Schema是MySQL自带的、较为底层的性能监控特性,提供一系列、具备自定义收集粒度的监控体系. 对MySQL服务执行过程中的各项事件(Events)的分析尤为重视. Performance Schema的精细化控制,主要通过performance_schema库下的一系列setup表来实现.

Elasticsearch Performance Tuning Practice at eBay

- -
Elasticsearch is an open source search and analytic engine based on Apache Lucene that allows users to store, search, analyze data in near real time. This document summarizes the challenges as well as the process and tools that the Pronto team builds to address the challenges in a strategic way.

译|High-Performance Server Architecture

- - 掘金 架构
本文的目的是分享我多年来关于如何开发某种应用程序的一些想法,对于这种应用程序,术语“服务”只是一个无力的近似称呼. 更准确地说,将写的与一大类程序有关,这些程序旨每秒处理大量离散的消息或请求. 网络服务通常最适合此定义,但从某种意义上讲,实际上并非所有的程序都是服务. 但是,由于“高性能请求处理程序”是很糟糕的标题,为简单起见,倒不如叫“服务”万事大吉.

ORACLE SQL Performance Analyzer的使用

- - CSDN博客数据库推荐文章
通过 SPA,您可以根据各种更改类型(如初始化参数更改、优化器统计刷新和数据库升级)播放特定的. SQL 或整个 SQL 负载,然后生成比较报告,帮助您评估它们的影响.. 在 Oracle Database 11g 之前的版本中,我必须捕获所有 SQL 语句,通过跟踪运行这些语句,. 然后得到执行计划 — 这是一项极其耗时又极易出错的任务.

tsung: 好文: PHP performance tips - Google Webmaster

- 小汐 - Planet DebianTW
Google 提供的 PHP 效能調校(Optimize performance)的幾點原則, 詳細可見此文:. 原文: Let's make the web faster - PHP performance tips. 作者: Eric Higgins, Google Webmaster. 此文內容很短, 講得都是大方向, 主題內容如下:.

SQL Performance Analyzer SPA常用脚本汇总

- - CSDN博客数据库推荐文章
附件为 一个SPA报告  spa_buffergets_summary. SQL 性能分析器 SQL Performance Analyzer SPA. Oracle Database 11g 引入了 SQL 性能分析器;使用该工具可以准确地评估更改对组成工作量的 SQL 语句的影响. SQL 性能分析器可帮助预测潜在的更改对 SQL 查询工作量的性能影响.

使用performance api监测页面性能

- - jackyrong
对于前端开发来说,知道整个页面从开始加载到有内容展示出来的时间是很重要的事情. 通常我们要知道页面加载的时间的话.是采用计算几个关键的时间点的方法来得出页面加载的时间.但是这个方式存在一些问题,比如:我们不知道浏览器在开始解析页面之前卸载前一个文档,解析dns的时间. 那么performance API是啥,能做啥和不能做啥呢.

18 Command Line Tools to Monitor Linux Performance(转)

- - Linux - 操作系统 - ITeye博客
This list of commands shown here are very enough for you to pick the one that is suitable for your monitoring scenario.. Top command is a performance monitoring program which is used frequently by many system administrators to monitor Linux performance and it is available under many.