Java Network Socket Read Performance and Disk Io

Java Programming Tutorial

Advanced Input & Output (I/O)

New I/O (java.nio) (JDK 1.4)

JDK one.four introduced the then-called New I/O (or NIO), in java.nio parcel and its auxiliary packages, to support high performance and intensive I/O operations. NIO is meant to complement the existing Standard I/O (in java.io package), not as a replacement.

NIO Buffers - Class java.nio.Buffer

IO_Processes.png

Concrete I/O functioning is thousands times slower than memory admission. Hence, a chunk of information is ofttimes enshroud or buffer to improve the throughput. Every bit illustrated from the above diagram, many layers of cache exist between your Java awarding and physical disk.

  • Deejay Buffer is RAM that is built into the deejay drive to shop a block of information from the disk. The cost of transferring data from the disk surface to the disk buffer is by far the slowest and the most expensive performance, because it involves physical movement of the disk.
  • OS Buffer: OS does its ain buffering as it tin can enshroud more data and manage it more elegantly. This buffer can as well exist shared amidst the applications.
  • Application Buffer: Application may optionally buffer its own data.

NIO data transfer is through the then-called buffers implemented in coffee.nio.Buffer grade. A Buffer is similar to an array, except that it is implemented much more efficiently by closely coupled with the underlying operating system. A Buffer is a contiguous, linear storage. Similar to an array, a Buffer has a stock-still capacity.

IO_NioBuffer.png

The is a buffer class for each of the archaic types (except boolean), as shown in the to a higher place diagram. The abstruse superclass coffee.nio.Buffer provides the common properties of all buffers, and ascertain a minor set of common operations.

A Buffer has a chapters, position, limit, and an optional mark:

  • The chapters must exist specified when the Buffer is constructed and cannot be changed (similar to an array). You can retrieve it via method capacity().
  • The limit specifies the current occupancy. In other word, the buffer contains valid data in the range 0 to limit-ane. Yous can retrieve the current limit via method limit() or set the limit via method limit(int newLimit). Limit shall non be greater than capacity.
  • Different assortment, there is a so-called position (or cursor) in a Buffer that indicates where the next piece of information is to be read or written. You tin can remember the current position via method position() or change the current position via method position(int newPosition). Position shall non exist greater than the limit.
  • A marker provide a positional mark. You tin mark the current position via the method marker().

Information Transfer (Get/Put): Each of the primitive buffers provides a set of get() and put() methods to read/write an element or a array of elements from/to the buffer. The position increases by the number of elements transferred. For example, the IntBuffer provides:

            public int          get()                   public int          go(int          position)       public IntBuffer          get(int[]          dest)   public IntBuffer get(int[]          dest, int          offset, int          length)    public IntBuffer          put(int          chemical element)                  public IntBuffer          put(int          position, int          element)    public IntBuffer          put(int[]          source)                 public IntBuffer          put(int[]          source, int          offset, int          length)

ByteBuffer is special. It provides boosted getXxx()/putXxx() methods to parse raw bytes into other archaic types. Information technology also can exist used every bit the sources and targets of I/O operations, which will exist explained later in channel I/O.

            public char          getChar()               public char          getChar(int          position)   public int          getInt() public int          getInt(int          position) public long          getLong() public long          getInt(long          position) public short          getShort() public short          getShort(int          position) public bladder          getFloat() public float          getFloat(int          position) public double          getDouble() public double          getDouble(int          position)        

Mark and Reset: Yous tin use mark() method to marking the current position. Invoking reset() sets the position to the previously-marked position. The marking may or may non exist set. If the mark is not set, invoking reset() triggers an InvalidMarkException. If the mark is set, information technology should never be greater than the position (considering the mark() marks the current position and position advances). The mark will be discarded when the position or the limit is adjusted to a value smaller than the mark. Hence, 0 ≤ marker ≤ position ≤ limit ≤ capacity.

Clear, Flip and Rewind:

  • clear(): sets the position to 0, limit to the capacity, and discards mark. It prepares the buffer for input.
  • flip(): sets the limit to the current position, position to 0, and discard mark. Buffer populated and fix for output.
  • rewind(): set the position to 0, and discard mark. It prepares the buffer for re-read.

Creating a Buffer: In that location are 3 ways to create a buffer:

  1. via method classify(int capacity), which allocates a new buffer, sets position to 0 and limit to capacity, and clear the marking.
  2. wrap an existing array into buffer via wrap(blazon[] array, int offset, int length) or wrap(type[] array) method.
  3. by creating a view of an existing ByteBuffer (to be discussed later).

Straight vs Indirect Buffers: A buffer can be direct or indirect. For a directly buffer, "the JVM will brand a best effort to perform native I/O operations directly upon it. That is, it will effort to avoid copying the buffer'due south content to (or from) an intermediate buffer before (or later on) each invocation of one of the underlying operating system'south native I/O operations." In other words, direct buffer is more efficient.

For byte buffer, you can classify a direct ByteBuffer via the allocateDirect(int capacity) method. For other buffers (char, curt, int, long, float, double), yous need to first allocate a ByteBuffer, and and then create a view via methods such as asFloatBuffer(). Equally these primitive types have unit of multiple bytes (e.thou., an int is 4 bytes), you need to specify the byte gild of either big-endian (big byte first) or little-endian (petty byte first) via order(ByteOrder order) method. The social club could be ByteOrder.BIG_ENDIAN, ByteOrder.LITTLE_ENDIAN, or ByteOrder.nativeOrder() which returns the native byte society of the underlying platform for you to write portable program.

ByteBuffer: ByteBuffer is special. To summarize:

  1. It is used in channel I/O (run into channel I/O below).
  2. You can allocate ByteBuffer equally direct. In this case, the JVM volition make a all-time effort to perform native I/O directly for better operation.
  3. You can create a view as other buffer, such as FloatBuffer via asFloatBuffer().
  4. You can get/put as other archaic types via getXxx() and putXxx().
  5. MapByteBuffer for mapped I/O.

Example: The following case allocates a direct FloatBuffer by creating a view of a direct ByteBuffer. Information technology then populates the FloatBuffer. [This segment of codes is used in OpenGL ES rendering.]

import java.nio.*; public form          TestDirectBuffer          {    public static void main(String[] args) {              float[] vertices = {           0.0f,  ane.0f, 0.0f,           -i.0f, -1.0f, 0.0f,            one.0f, -1.0f, 0.0f         };         FloatBuffer vertexBuffer;                         ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);                     vbb.lodge(ByteOrder.nativeOrder());                     vertexBuffer = vbb.asFloatBuffer();              vertexBuffer.put(vertices);              vertexBuffer.position(0);                    } }

More than Examples [TODO]

java.nio.MappedByteBuffer

MappedByteBuffer is a then-called straight buffer that is managed by the OS, instead of the Coffee application. In other words, MappedByteBuffer tin can be used to wrap a region of Bone buffer. Application can allocate different directly buffer to view the different portion of the Os buffer. [TODO more]

Channels (coffee.nio.channels.Channel)

A aqueduct represents a connection to a physical I/O device (such as file, network socket, or even some other program). It is similar to Standard I/O'south stream, but a more platform-dependent version of stream. Because channels have a closer ties to the underlying platform, they tin can achieve improve I/O throughput. The types of channel include:

  • FileChannel
  • SocketChannel: support non-blocking connexion for TCP socket.
  • DatagramChannel: UDP Datagram-oriented socket.

A Aqueduct object can exist obtained by calling the getChannel() methods of classes such as java.io.FileInputStream, java.io.FileOutputStream, java.io.RandomAccessFile, java.internet.Socket, java.net.ServerSocket, java.cyberspace.DatagramSocket, and java.net.MulticastSocket.

For example, yous can obtained a FileChannel as follows:

FileInputStream fis = new FileInputStream("in.dat"); FileChannel fc = fis.getChannel();  FileChannel fc = new FileInputStream("in.dat").getChannel();

A FileChannel obtained from a FileInputStream is read-merely; while a FileChannel obtained from a FileOutputStream is write-only. While Stream I/O processes 1 byte at at time; channel I/O reads/write a buffer at a time. In standard I/O'southward stream, data is read/write into/from a byte or a byte-array. For FileChannel, information is transferred via a ByteBuffer object in read()/write() methods.

public abstract int          read(ByteBuffer dest) public abstract int          write(ByteBuffer source)

You can transfer data betwixt an input channel and an output channel direct via:

public abstruse long          transferFrom(ReadableByteChannel source, long position, long count) public abstract long          transferTo(long position, long count, WritableByteChannel target)

Case: Copying a file using FileChannel

import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel;   public form FileChannelCopyJDK7 {    public static void main(String[] args) {       String inFileStr = "examination-in.jpg";       String outFileStr = "test-out.jpg";       long startTime, elapsedTime;         int bufferSizeKB = iv;       int bufferSize = bufferSizeKB*1024;                File fileIn = new File(inFileStr);       System.out.println("File size is " + fileIn.length() + " bytes");       Arrangement.out.println("Buffer size is " + bufferSizeKB + " KB");                System.out.println("Using FileChannel with an indirect ByteBuffer of " + bufferSizeKB + " KB");       endeavor (FileChannel in = new FileInputStream(inFileStr).getChannel();            FileChannel out = new FileOutputStream(outFileStr).getChannel()) {                    ByteBuffer bytebuf = ByteBuffer.allocate(bufferSize);            startTime = Organisation.nanoTime();          int bytesCount;          while ((bytesCount = in.read(bytebuf)) > 0) {                           bytebuf.flip();             out.write(bytebuf);               bytebuf.clear();               }          elapsedTime = Organization.nanoTime() - startTime;          System.out.println("Elapsed Time is "                + (elapsedTime / meg.0) + " msec");       } take hold of (IOException ex) {          ex.printStackTrace();       }                System.out.println("Using FileChannel with a direct ByteBuffer of " + bufferSizeKB + " KB");       endeavor (FileChannel in = new FileInputStream(inFileStr).getChannel();            FileChannel out = new FileOutputStream(outFileStr).getChannel()) {                    ByteBuffer bytebuf = ByteBuffer.allocateDirect(bufferSize);            startTime = Organization.nanoTime();          int bytesCount;          while ((bytesCount = in.read(bytebuf)) > 0) {                           bytebuf.flip();             out.write(bytebuf);               bytebuf.clear();               }          elapsedTime = System.nanoTime() - startTime;          System.out.println("Elapsed Time is "                + (elapsedTime / one thousand thousand.0) + " msec");       } grab (IOException ex) {          ex.printStackTrace();       }                Organization.out.println("Using FileChannel with transferTo()");       try (FileChannel in = new FileInputStream(inFileStr).getChannel();            FileChannel out = new FileOutputStream(outFileStr).getChannel()) {          startTime = System.nanoTime();          in.transferTo (0, in.size(), out);          elapsedTime = Arrangement.nanoTime() - startTime;          System.out.println("Elapsed Time is "                + (elapsedTime / million.0) + " msec");       } catch (IOException ex) {          ex.printStackTrace();       }                System.out.println("Using Buffered Stream");       try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFileStr));            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outFileStr))) {          startTime = System.nanoTime();          int bytesCount;          while ((bytesCount = in.read()) != -1) {             out.write(bytesCount);          }          elapsedTime = Arrangement.nanoTime() - startTime;          Arrangement.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");       } catch (IOException ex) {          ex.printStackTrace();       }                Organization.out.println("Using a programmer-managed byte-array of " + bufferSizeKB + " KB");       effort (FileInputStream in = new FileInputStream(inFileStr);            FileOutputStream out = new FileOutputStream(outFileStr)) {          startTime = System.nanoTime();          byte[] byteArray = new byte[bufferSize];              int bytesCount;          while ((bytesCount = in.read(byteArray)) != -1) {             out.write(byteArray, 0, bytesCount);          }          elapsedTime = System.nanoTime() - startTime;          System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");       } grab (IOException ex) {          ex.printStackTrace();       }    } }
File size is 1378093 bytebuffer Buffer size is 4 KB  Using FileChannel with an indirect ByteBuffer of 4 KB Elapsed Fourth dimension is 14.649701 msec  Using FileChannel with a direct ByteBuffer of iv KB Elapsed Time is 8.032151 msec  Using FileChannel with transferTo() Elapsed Time is 3.573988 msec  Using Buffered Stream Elapsed Time is 125.604174 msec  Using a developer-managed byte-array of four KB Elapsed Time is 5.642199 msec

FileChannel with a 4K direct ByteBuffer is faster than indirect ByteBuffer. Buffered Stream I/O is many times slower than FileChannel. However, it is interesting to note that the programmer-managed byte-array is faster than some channels?!

The following tabular array compare the run-fourth dimension for various buffer size with (a) Using FileChannel with an indirect ByteBuffer, (b) Using FileChannel with a direct ByteBuffer, (c) Using FileChannel with transferTo(), (d) Using Buffered Stream, (e) Using a programmer-managed byte-array.

BufSize   (a)    (b)    (c)    (d)    (e)    4KB  sixteen.67   ix.73          3.33          124.21   vii.72   16KB   vi.92   3.39          i.86          110.85   four.06   32KB   three.95   2.75          1.76          109.60   2.90   64KB   three.26   ii.15          1.88          109.77   2.96  128KB   ii.77   2.11          ii.02          109.64   ii.59  256KB   2.49          1.66          1.lxxx 109.10   2.55 1024KB   3.57          1.86          one.97 109.08   5.88

[PENDING] Network I/O with NIO. SocketChannel and DatagramChannel.

Selectors

A number of channels can be registered with a selector (java.nio.channels.Selector). A selector provides a mechanism for waiting on channels until one ore more become available for information transfer. It tin be used to block the plan until at least ane channel is available for use. Examples are server applications that involves simultaneously waiting for responses on a number of session. [TODO]

Grapheme Ready (Charset) - java.nio.charset package

[Covered in Basic I/O]

Regular Expression - coffee.util.regex package

[TODO in regexe chapter]

Advanced I/O in JDK 7

[TODO]

LINK TO JAVA REFERENCES & Resource

More REFERENCES & Resource

  1. Java Online Tutorial on "Basic I/O" @ http://download.oracle.com/javase/tutorial/essential/io/index.html, in particular "File I/O (Featuring NIO.2)".

hollinstheivein88.blogspot.com

Source: https://www3.ntu.edu.sg/home/ehchua/programming/java/J5b_IO_advanced.html

0 Response to "Java Network Socket Read Performance and Disk Io"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel