一次诡异的NIO和IO性能测试

来源:互联网 发布:东兴证券下载软件 编辑:程序博客网 时间:2024/06/06 14:12

一次诡异的NIO和IO性能测试

1 NIO

NIO是jdk1.4推出的新IO,和之前的IO最大的不同就是NIO采用了虚拟内存,普通的IO如果从磁盘文件读取一个文件需要经过这借步骤,首先从磁盘文件中读取一定的字节到内核缓冲区中,然后再拷贝到用户空间,如图:

这里写图片描述

而NIO采用虚拟内存,将应用程序的buffer和内核的buffer都作为虚拟内存,并且两块不同的虚拟内存指向相同的物理内存,内核通过DMA将数据读取到buffer的时候,应用程序就可以直接使用这些数据了。省去了从内核缓冲区拷贝数据到用户空间,如图:

这里写图片描述

为什么普通的IO需要经过内核这一环节?

因为在有虚拟内存之前,用户读取磁盘文件需要进行文件操作的一些系统调用,当用户态读取文件是,陷入到内核态,内核态空间和用户态空间是不同的空间,当内核态读取文件需要拷贝到用户态。

2 NIO和IO的性能测试

package forfun;import java.io.*;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;/** * * @author Jackie * @date 2017/12/15 */public class SimpleFileTransferTest {    private long transferFile(File source, File des) {        long startTime=System.currentTimeMillis();        InputStream read = null;        OutputStream write = null;        try {            if (!des.exists())                des.createNewFile();            byte[] buffer = new byte[1024*1024];//1M缓冲区            read = new FileInputStream(source);            write = new FileOutputStream(des);            int size = -1;            while ((size = read.read(buffer)) > 0) {                write.write(buffer, 0, size);            }        }catch (Exception e) {            e.printStackTrace();        }finally {            try {                read.close();                write.close();            } catch (IOException e) {                e.printStackTrace();            }        }        long endTime=System.currentTimeMillis();        return endTime - startTime;    }    private long transferFileWithNIO(File source, File des) {        long startTime=System.currentTimeMillis();        FileChannel readChannel = null;        FileChannel writeChannel = null;        try {            if (!des.exists())                des.createNewFile();            RandomAccessFile read = new RandomAccessFile(source, "rw");            RandomAccessFile write = new RandomAccessFile(des, "rw");            readChannel = read.getChannel();            writeChannel = write.getChannel();            long a = System.currentTimeMillis();            ByteBuffer byteBuffer = ByteBuffer.allocate(1024*1024);//1M缓冲区            long b = System.currentTimeMillis();            System.out.println(b - a);            while (readChannel.read(byteBuffer) > 0) {                byteBuffer.flip();                writeChannel.write(byteBuffer);                byteBuffer.clear();            }        }catch (Exception e) {            e.printStackTrace();        }finally {            try {                writeChannel.close();                readChannel.close();            } catch (IOException e) {                e.printStackTrace();            }        }        long endTime=System.currentTimeMillis();        return endTime - startTime;    }    public static void main(String[] args) throws FileNotFoundException {        SimpleFileTransferTest simpleFileTransferTest = new SimpleFileTransferTest();        File sourse = new File("/Users/macbookpro/Downloads/飘花电影piaohua.com消失的爱人BD1280高清中英双字.rmvb");        File des = new File("/Users/macbookpro/Desktop/des.rmvb");        File nio = new File("/Users/macbookpro/Desktop/nio.rmvb");        long timeNio = simpleFileTransferTest.transferFileWithNIO(sourse, nio);        System.out.println(timeNio + "NIO时间");        long time = simpleFileTransferTest.transferFile(sourse, des);        System.out.println(time + "普通字节流时间");    }}

程序很简单,就是用IO和NIO拷贝一个文件到桌面,让我们看下测试结果:

第一次测试:

这里写图片描述

呃呃呃,第一次不算……再来一次

第二次测试:
这里写图片描述
什么情况?不服,再来一次

第三次测试:
这里写图片描述

NIO不是性能比IO要好么,但是这几个测试没有表明NIO比IO性能高啊,反而比IO性能还低。三次测试结果是我陷入深思,难道我的程序写的有问题?重新检查了一下,发现并没有问题,事实胜于雄辩。

3 答案

测试的结果与我的认知产生了分歧,然而我相信NIO的性能是要高于IO的,于是我去查阅资料,就是这本大部头
这里写图片描述

找到IO这一章,其中有这么一段文字:JDK 1.4的java.,nio,*包中引入了心得java IO类库,其目的在于提高速度,实际上,旧的IO包已经使用NIO重新实现过,以便充分利用这种速度提高。

不由感叹还有这种操作。

原创粉丝点击