`

(转)Java NIO(内存映射文件) 与 传统IO 读取 性能测试

    博客分类:
  • JAVA
 
阅读更多

转:http://jackyin5918.iteye.com/blog/2024231

 

package io;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Java NIO(内存映射文件) 与 传统IO 读取 性能测试
 * 
 * 读取 RandomAccessFile 类读写测试及其性能优化(一) 
 * (链接 http://jackyin5918.iteye.com/blog/2022888 )中
 * GenerateIntArray 生成的并保存到文件的数据.
 * 测试时读取1千万个整型构成的二进制文件38.1M
 * 
 * 由测试结果分析可知:
 * 
 * readData(f) -- 普通IO方式读取
 * readDataNIO(f) -- NIO Channel,Buffer方式读取
 * readDataNIO_D(f) -- NIO中Buffer使用 直接方式分配空间(allocateDirect)
 * readDataMap_M(f) -- 多线程中使用 内存映射文件
 * readDataMap(f) -- 单线程中使用内存映射文件读取
 * 
 * NIO方式使用直接分配Buffer空间方式读取性能最好,甚至超过了内存映射文件
 * (可能是文件还不够大,如果文件达到1000M以上应该是内存映射文件性能最好).
 * 
 * 普通NIO方式 耗时 是NIO_D方式的2倍.
 * 
 * 传统IO方式读取文件,耗时 是NIO的 上百倍.
 * 
 * 内存映射文件,在文件较大(大小达到几十M时)可以显著提升性能.
 * 多线程中使用内存映射文件 没有 提高性能.

----------------------测试结果---------
count = 1000, size = 10000 

正在读取数据,请稍后...
readData(f) 读取数据成功, 耗时:411326

正在读取数据,请稍后...
readDataNIO_D(f) 读取数据成功, 耗时:4161

正在读取数据,请稍后...
readDataNIO(f) 读取数据成功, 耗时:10645

正在读取数据,请稍后...
readDataMap_M(f) 读取数据成功, 耗时:6682

正在读取数据,请稍后...
readDataMap 读取数据成功, 耗时:4841

 */
public class GetTheMiddle
{
  private int     count = 10; // 数组的个数,
  private int     size  = 1000;   // 每个数组的元素个数
  private int[][] dataArr;

  public GetTheMiddle()
  {
    dataArr = new int[count][size];
  }

  public GetTheMiddle(int count, int size)
  {
    this.count = count;
    this.size = size;
    this.dataArr = new int[count][size];
  }

  public int[][] getDataArr()
  {
    return dataArr;
  }

  public int[][] readData(File f)
  {
    try
    {
      RandomAccessFile rf = new RandomAccessFile(f, "r");
      for (int i = 0; i < count; i++)
      {
        for (int j = 0; j < size; j++)
        {
          dataArr[i][j] = rf.readInt();
        }
      }
      rf.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    return dataArr;
  }
  
  public int[][] readDataNIO(File f)
  {
    try
    {
      RandomAccessFile rf = new RandomAccessFile(f, "r");
      FileChannel fc = rf.getChannel();
      ByteBuffer buffer = ByteBuffer.allocate(size * 4);
      
      for (int i = 0; i < count; i++)
      {
        fc.read(buffer);
        buffer.rewind();
        for (int j = 0; j < size; j++)
        {
          dataArr[i][j] = buffer.getInt();
        }
        buffer.rewind();
      }
      rf.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    return dataArr;
  }
  
  public int[][] readDataNIO_D(File f)
  {
    try
    {
      RandomAccessFile rf = new RandomAccessFile(f, "r");
      FileChannel fc = rf.getChannel();
      ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4);
      
      for (int i = 0; i < count; i++)
      {
        fc.read(buffer);
        buffer.rewind();
        for (int j = 0; j < size; j++)
        {
          dataArr[i][j] = buffer.getInt();
        }
        buffer.rewind();
      }
      rf.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    return dataArr;
  }
  
  public int[][] readDataMap(File f)
  {
    try
    {
      RandomAccessFile rf = new RandomAccessFile(f, "r");
      FileChannel fc = rf.getChannel();
      
      int mapSize = size * 4;
      for (int i = 0; i < count; i++)
      {
        int position = i * size * 4;
        MappedByteBuffer mBuffer = fc.map(MapMode.READ_ONLY,position,mapSize);
        
        for (int j = 0; j < size; j++)
        {
          dataArr[i][j] = mBuffer.getInt();
        }
      }
      rf.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    return dataArr;
  }
  
  class ReadDataTask implements Runnable
  {

    private File f;
    private int dataIndex;
    
    public ReadDataTask(File f,int dataIndex)
    {
      this.f = f;
      this.dataIndex = dataIndex;
    }
    
    @Override
    public void run()
    {
      try
      {
        RandomAccessFile rf = new RandomAccessFile(f, "r");
        FileChannel fc = rf.getChannel();
        
        int mapSize = size * 4;
        int position = dataIndex * size * 4;
        
        MappedByteBuffer mBuffer = fc.map(MapMode.READ_ONLY,position,mapSize);
        
        for (int j = 0; j < size; j++)
        {
          dataArr[dataIndex][j] = mBuffer.getInt();
        }
        rf.close();
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }
    }
    
  }
  
  public int[][] readDataMap_M(File f)
  {
    try
    {
      ExecutorService exec = Executors.newCachedThreadPool();
      for(int i=0;i<count;i++)
      {
        exec.execute(new ReadDataTask(f,i));
      }
      exec.shutdown();
      while(true)
      {
        if(exec.isTerminated()) break;
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    
    return dataArr;
  }

  public static void main(String[] args)
  {
    int count = 1000;
    int size = 10000;
    boolean bPrintData = false; // 是否打印生成的数组,当数据量大是不打印,只在小数据量时打印以便测试
    boolean bRefreshData = true; //是否重新生成数据,第一次测试时生成数据后,改成false不必重新生成数据
    
    System.out.printf("count = %d, size = %d \n\n", count, size);
    GetTheMiddle gm = new GetTheMiddle(count,size);
    GenerateIntArray generator = new GenerateIntArray(count, size);

    File f;
    try
    {
      f = new File("D:\\D\\test_data.dat");
      if(bRefreshData)
      {
        generator.refreshDataArr();
        generator.writeData2File_B(f);
      }
      
      System.out.println("正在读取数据,请稍后...");
      long startTmie = System.nanoTime();
      gm.readData(f);
      long totalTime = (System.nanoTime() - startTmie)/ 100000;
      System.out.println("readData(f) 读取数据成功, 耗时:" + totalTime);
      System.out.println();
      
      System.out.println("正在读取数据,请稍后...");
      startTmie = System.nanoTime();
      gm.readDataNIO_D(f);
      totalTime = (System.nanoTime() - startTmie)/ 100000;
      System.out.println("readDataNIO_D(f) 读取数据成功, 耗时:" + totalTime);
      System.out.println();
      
      System.out.println("正在读取数据,请稍后...");
      startTmie = System.nanoTime();
      gm.readDataNIO(f);
      totalTime = (System.nanoTime() - startTmie)/ 100000;
      System.out.println("readDataNIO(f) 读取数据成功, 耗时:" + totalTime);
      System.out.println();
      
      System.out.println("正在读取数据,请稍后...");
      startTmie = System.nanoTime();
      gm.readDataMap_M(f);
      totalTime = (System.nanoTime() - startTmie)/ 100000;
      System.out.println("readDataMap_M(f) 读取数据成功, 耗时:" + totalTime);
      System.out.println();
      
      
      System.out.println("正在读取数据,请稍后...");
      startTmie = System.nanoTime();
      gm.readDataMap(f);
      totalTime = (System.nanoTime() - startTmie)/ 100000;
      System.out.println("readDataMap 读取数据成功, 耗时:" + totalTime);
      System.out.println();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    
    if(bPrintData)
    {
      System.out.println("generator中生成的数据...");
      int[][] intArr = generator.getDataArr();
      for (int i = 0; i < count; i++)
      {
        for (int j = 0; j < size; j++)
        {
          System.out.printf("%1$3d", intArr[i][j]);
        }
        System.out.println();
      }
      
      System.out.println("读取出来的数组...");
      intArr = gm.getDataArr();
      for (int i = 0; i < count; i++)
      {
        for (int j = 0; j < size; j++)
        {
          System.out.printf("%1$-5s", intArr[i][j]);
        }
        System.out.println();
      }
    }
  }

}

 

分享到:
评论

相关推荐

    尚硅谷Java视频_NIO 视频教程

    尚硅谷_NIO_通道的数据传输与内存映射文件 ·06. 尚硅谷_NIO_分散读取与聚集写入 ·07. 尚硅谷_NIO_字符集 Charset ·08. 尚硅谷_NIO_阻塞与非阻塞 ·09. 尚硅谷_NIO_阻塞式 ·10. 尚硅谷_NIO_非阻塞式 ·11. ...

    Java性能优化之使用NIO提升性能(Buffer和Channel)

    在软件系统中,由于IO的速度要比内存慢,因此,I/O读写在很多场合都会成为系统的瓶颈。提升I/O速度,对提升系统整体性能有着很大的好处。...支持锁和内存映射文件的文件访问接口;提供了基于Selector的异步网

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA_API1.6文档(中文)

    java.io 通过数据流、序列化和文件系统提供系统输入和输出。 java.lang 提供利用 Java 编程语言进行程序设计的基础类。 java.lang.annotation 为 Java 编程语言注释设施提供库支持。 java.lang.instrument 提供...

    java开源包4

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包11

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包6

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包9

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包101

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包5

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包8

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包10

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包1

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包3

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    Java 1.6 API 中文 New

    java.io 通过数据流、序列化和文件系统提供系统输入和输出。 java.lang 提供利用 Java 编程语言进行程序设计的基础类。 java.lang.annotation 为 Java 编程语言注释设施提供库支持。 java.lang.instrument 提供允许 ...

    java api最新7.0

    java.io 通过数据流、序列化和文件系统提供系统输入和输出。 java.lang 提供利用 Java 编程语言进行程序设计的基础类。 java.lang.annotation 为 Java 编程语言注释设施提供库支持。 java.lang.instrument 提供允许 ...

    java开源包2

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

    java开源包7

    Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...

Global site tag (gtag.js) - Google Analytics