Search code examples
javaionio

NIO and IO performance issue (first and second read and write) in Centos 7


I have coded to read and write file using NIO and IO. Then I have performed simple performance test in the same disk environment. My test was to read a file (~5MB) from a directory and write it in the different directory (same disk).

First test (test.pdf):

  • NIO: Elasped time: 80.457224 msec
  • IO: Elasped time: 4.51824 msec

Second test, using same file (test.pdf):

  • NIO: Elasped time: 4.732797 msec
  • IO: Elasped time: 4.059444 msec

My question is why in the first test, NIO took longer time than IO and in the second test why NIO took almost same time as IO? I am little bit confused.

Here is the code snippet (very basic, well known code):

int BUFFER_SIZE = 64 * 1024;

NIO:

ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
try (SeekableByteChannel seekableChannelToRead =  Files.newByteChannel(readFilePath,EnumSet.of(StandardOpenOption.READ));
     SeekableByteChannel seekableChannelToWrite  = Files.newByteChannel(writeFilePath, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE))) {

  Long startTime = System.nanoTime();
  int byteCount = 0;

  while ((byteCount = seekableChannelToRead.read(buffer)) > 0) {
        buffer.flip();
        seekableChannelToWrite.write(buffer);
        buffer.clear();
  }

  Long elapsedTime = System.nanoTime() - startTime;
  System.out.println("FileName: " + path.getFileName() + "; Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");

} catch (Exception e) {
    e.printStackTrace();
}

IO:

try (FileInputStream in = new FileInputStream(path.toFile());
   FileOutputStream out = new FileOutputStream(writeFilePath.toFile())) {
   Long startTime = System.nanoTime();
   byte[] byteArray = new byte[BUFFER_SIZE]; // byte-array
   int bytesCount;
   while ((bytesCount = in.read(byteArray)) != -1) {
        out.write(byteArray, 0, bytesCount);
   }
   Long elapsedTime = System.nanoTime() - startTime;
   System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");
} catch (IOException ex) {
    ex.printStackTrace();
}

Solution

  • The first test ran slow because the file had to be loaded from your disk storage the first time.

    Loading the file on a 7200rpm drive in 80ms is not necessarily abnormal. Your drive probably has a seek time of about 8ms and we don't know if the file is fragmented or not.

    After loading the file is stored in buffer cache and subsequent requests (even different processes) are loaded much faster. The kernel stores files in the buffer cache to speedup access time for commonly used files.

    When doing benchmarks, its usually a good idea to perform the tests entirely in memory... or prefetch the file contents so it exists in the buffer cache.