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
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.
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 methodcapacity()
. - 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 thelimit
via methodlimit(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 methodposition()
or change the current position via methodposition(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 theposition
to 0,limit
to thecapacity
, and discardsmark
. It prepares the buffer for input. -
flip()
: sets thelimit
to the currentposition
,position
to 0, and discardmark
. 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:
- via method
classify(int capacity)
, which allocates a new buffer, sets position to 0 and limit to capacity, and clear the marking. - wrap an existing array into buffer via
wrap(blazon[] array, int offset, int length)
orwrap(type[] array)
method. - 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:
- It is used in channel I/O (run into channel I/O below).
- 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. - You can create a view as other buffer, such as FloatBuffer via
asFloatBuffer()
. - You can get/put as other archaic types via
getXxx()
andputXxx()
. -
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
- 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