【问题标题】:Performance when Reading single byte vs many at a time?一次读取单个字节与多个字节时的性能?
【发布时间】:2012-07-15 03:57:08
【问题描述】:

我正在尝试比较 InputStream.read()InputStream.read(byte[] b) 的性能。

考虑到InputStream 类的read(b, off, len) 方法只是重复调用read() 方法,InputStream.read(byte[] b) 在某种程度上更快吗?

【问题讨论】:

    标签: java inputstream


    【解决方案1】:

    您不应混淆 InputStream 的默认行为及其大多数子类的行为。 OO 设计的一个原则是子类可以改变该实现的方法的行为。

    从 InputStream - read(byte[]) 重复调用 read()。

    public int read(byte b[], int off, int len) throws IOException {
       // code removed
    
            for (; i < len ; i++) {
                c = read();
    
       // code removed
    }
    

    从 BufferedInputStream - read(byte[]) 不调用 read()。

    public synchronized int read(byte b[], int off, int len) throws IOException {
       // code removed
            int nread = read1(b, off + n, len - n);
       // code removed
    }
    
    private int read1(byte[] b, int off, int len) throws IOException {
       // code removed
                return getInIfOpen().read(b, off, len);
       // code removed
    }
    

    从 FileInputStream - read(byte[]) 不调用 read()。

    public int read(byte b[], int off, int len) throws IOException {
        return readBytes(b, off, len);
    }
    
    private native int readBytes(byte b[], int off, int len) throws IOException;
    

    虽然 InputStream 一次读取一个字节,但几乎所有实现都会将 read(byte[]) 传递给底层流中的相同方法。

    注意:read(byte[], int, int) 的实现在所有三种情况下都不同。

    我要更清楚地问的是:假设我想读取 20 个字节,一次读取一个字节会在循环中每次都命中底层流(例如文件系统),这意味着 20 次..ok 现在正在阅读一次 20 个字节的数组,即使用 read(byte[] 20),现在这将访问底层流(例如文件系统)一次或 20 次..?? (正如它给出的那样: read(byte[] b) 方法也将重复调用方法 read() 20次)??

    无论您使用 BufferedInputStream 还是 FileInputStream,一次 read(byte[]) 最多会导致一次系统调用来读取 byte[]。

    【讨论】:

    • PeterLawrey:感谢您出色的解释.. 这是否意味着 InputStream 的所有 3 种方法一次最多读取一个字节,而与我们在 read(byte[] 中指定的字节数无关) ??
    • 不,我试图详细说明为什么不是这样。我不清楚你为什么会相信会是这种情况。
    • 还有一件事,如果使用 BufferedInputStream,创建字节缓冲区并使用 read(byte[]) 方法读取的任何优势,而不是逐字节读取它?
    • 优势要小得多。使用 read(byte[]) 仍然会稍微快一些,因为它调用 BufferedInputStream 的频率较低。注意:如果您正在读取 16KB 或更大的大缓冲区,使用 BufferedInputStream 可能无济于事(如果它的缓冲区更小)
    • Peter Lawrey 非常感谢,BufferedInputStream 是否通过简单的 read() 方法调用使用或持有任何默认缓冲区大小,或者这是在内部建立查看数据大小,我的意思是没有明确指定缓冲区大小.
    【解决方案2】:

    使用您认为最方便的方式,但请记住将您的 InputStream 包装为 BufferedInputStream

    如果没有缓冲单个 read() 将在您每次阅读时访问底层流(例如文件系统)。通过缓冲相同的 read() 加载一个块(例如 4KiB)并对其进行缓冲。显然从磁盘读取(即使存在一些较低级别的操作系统/硬盘缓存)要慢得多。

    因此,read(byte[] b) 仅在您的流未缓冲或您确实想读取多个字节时更好。

    【讨论】:

    • 一次读取一个字符/字节(即 InputStream.read()),或者一次读取一个字节/字符数组一个块..读取时有什么区别(字节 [ ] b) 方法也会重复调用方法 read() 字节/字符数组一个块声明的次数?
    • @Tomasz Nurkiewicz:谢谢,但不包括 BufferedInputStream 的情况。如果我们只谈论 InputStream..那么这两种方法都会导致相同的性能..说的是真的吗?
    • @AshishKataria 你只是在这里重复最初的问题,他已经回答了。如果您插入 BufferedInputStream,,则该操作中没有单字节读取操作,这就是它的用途。
    • @EJP..thanks 但是忘记 BufferedInputStream 的例子:我要更清楚地问的是:假设我想读取 20 个字节,一次读取一个字节会命中底层流(例如文件系统)每次在一个循环中,这意味着 20 次..ok 现在一次读取 20 个字节的数组,即使用 read(byte[] 20),现在这将访问底层流(例如文件系统)一次或20次..?? (正如它给出的那样: read(byte[] b) 方法也将重复调用方法 read() 20次)??
    • @AshishKataria 你引用了一个抽象类。请引用一个不覆盖该方法的具体实现类。
    猜你喜欢
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    相关资源
    最近更新 更多