当前位置: 首页 > 面试题库 >

Java NIO FileChannel与FileOutputstream的性能/有用性

何涵育
2023-03-14
问题内容

我试图弄清楚当我们使用nio FileChannel和normal FileInputStream/FileOuputStream来读写文件到文件系统时,性能(或优势)是否存在任何差异。我观察到,在我的机器上,两者的性能都相同,而且FileChannel速度也慢了很多倍。我能否请你比较这两种方法的更多详细信息。这是我使用的代码,正在测试的文件在左右350MB。如果我不考虑随机访问或其他此类高级功能,是否可以将基于NIO的类用于文件I / O是一个好选择吗?

package trialjavaprograms;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class JavaNIOTest {
    public static void main(String[] args) throws Exception {
        useNormalIO();
        useFileChannel();
    }

    private static void useNormalIO() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        InputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        byte[] buf = new byte[64 * 1024];
        int len = 0;
        while((len = is.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.flush();
        fos.close();
        is.close();
        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }

    private static void useFileChannel() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        FileInputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        FileChannel f = is.getChannel();
        FileChannel f2 = fos.getChannel();

        ByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024);
        long len = 0;
        while((len = f.read(buf)) != -1) {
            buf.flip();
            f2.write(buf);
            buf.clear();
        }

        f2.close();
        f.close();

        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }
}

问题答案:

我对大型文件的体验java.nio比更快java.io。 确实更快。 例如在> 250%的范围内。也就是说,我正在消除明显的瓶颈,我认为这可能会影响你的微基准测试。调查的潜在领域:

缓冲区大小。 你基本上拥有的算法

  • 从磁盘复制到缓冲区
  • 从缓冲区复制到磁盘

我自己的经验是,此缓冲区大小已经可以调整。我为应用程序的一部分分配了4KB,为另一部分分配了256KB。我怀疑你的代码正在遭受如此大的缓冲区。使用1KB,2KB,4KB,8KB,16KB,32KB和64KB的缓冲区运行一些基准测试以向自己证明。

不要执行读写同一磁盘的Java基准测试。

如果这样做,那么你实际上是在对磁盘进行基准测试,而不是对Java进行基准测试。我还建议,如果你的CPU不忙,那么你可能会遇到其他瓶颈。

如果不需要,请不要使用缓冲区。

如果目标是其他磁盘或NIC,为什么还要复制到内存中?对于较大的文件,确保的延迟是不平凡的。

就像其他人所说的那样,请使用FileChannel.transferTo()FileChannel.transferFrom()。此处的主要优点是,JVM使用操作系统对DMA(直接内存访问)的访问(如果存在)。(这取决于实现方式,但是可以在通用CPU上使用现代的Sun和IBM版本。) 发生的情况是数据直接往返于磁盘,总线,然后直接到达目标……绕过任何电路RAM或CPU。

我日夜不停地工作的Web应用程序非常繁忙。我也做了微观基准和现实基准。结果在我的博客上,看看:

  • 实际性能指标:java.io与java.nio
  • 实际性能指标:java.io与java.nio(续集)

使用生产数据和环境

微观基准易于失真。如果可以,请根据预期的负载,在预期的硬件上,按照计划要做的事情来收集数据。

我的基准是可靠且可靠的,因为它们是在生产系统,强大的系统,有负载的系统以及日志中收集的。 而不是我笔记本的7200 RPM 2.5英寸SATA驱动器,而当我密切关注JVM在硬盘上工作时。

你在做什么?这很重要。



 类似资料:
  • 问题内容: 我有一个模块,负责读取,处理和将字节写入磁盘。字节通过UDP传入,并且在组装完各个数据报之后,要处理并写入磁盘的最终字节数组通常在200字节至500,000字节之间。有时,组装后会有字节数组超过500,000个字节,但是这些数组相对较少。 我目前正在使用的方法。我还尝试将包裹在中,包括使用接受缓冲区大小作为参数的构造函数。 看来,使用会趋向于稍微提高性能,但是我才刚刚开始尝试使用不同的

  • 问题内容: 为了简单起见,最好在不占用大量CPU的前提下使用该功能,或者该走的路要走吗? 问题答案: 我认为您正在进行简单的优化。regexp表达式的计算是如此昂贵,以至于结果被缓存起来,希望将来可以再次使用。如果您实际使用不同的字符串进行转换,您会发现适度的翻译自然是更快的,因为它是其专门功能。 这是我的示例,在上运行: 于: 结论:总的来说,我怀疑会赢。

  • 问题内容: 我们有一个本机应用程序,它使用GPU(OpenCL)通过一种特定的方法处理大数据,并且运行得很好,没有问题。该项目的一部分(网络和分发)由进行开发,我们只需要调用本机应用程序/库即可。 我们试图使用类将其称为独立的外部过程。问题是我们无法控制应用程序(事件,处理程序,线程等)。我们还尝试将C代码转换为Java代码,但是性能下降了。除了将本机代码作为进程运行之外,我还在考虑JNA和JNI

  • 问题内容: 似乎在这么晚的时候这样做很疯狂,但是… 我正在使用Rocket Software UniVerse源和SQL目标重建一些ETL基础结构。旧的目标平台是Windows Server 2003上的SQL 2000,新的平台是Windows Server 2012上的SQL2012。在两种情况下,都使用ODBC驱动程序连接到源。一切似乎都可以在新平台上正常运行,但包的执行时间却成倍降低。例如

  • 概览 首先我们了解一下 YODAOS 的运行时:YODAOS 基于 ShadowNode 它采用事件驱动、非阻塞I/O模型;在设计之初,ShadowNode 的接口与 Node.js 兼容,因此在大部分场景下,开发者可以像 Node.js 一样使用 ShadowNode,了解这些有利于开发者更快速的进行 YODAOS 上的应用开发。 YODAOS 开发应用时,需要关注应用的性能与稳定性,包括但不限

  • 我试图用progressbar修改Koush的下载示例中的代码,使其写入FileOutputStream而不是File,但eclipse给出了以下错误: ResponseFuture类型未定义方法progressHandler(new ProgressCallback(){}) 代码如下: