Sponsored Link •
System I/O can be blocking, or non-blocking synchronous, or
non-blocking asynchronous [1, 2].
Blocking I/O means that the calling
system does not return control to the caller until the operation is finished. As a result, the caller is
blocked and cannot perform other activities during that time. Most important, the caller thread
cannot be reused for other request processing while waiting for the I/O to complete, and
becomes a wasted resource during that time.
read() operation on a socket in blocking mode will not return control if the socket buffer
is empty until some data becomes available.
By contrast, a non-blocking synchronous call returns control to the caller immediately. The caller is not made to
wait, and the invoked system immediately returns one of two responses: If the call was executed
and the results are ready, then the caller is told of that.
Alternatively, the invoked system can tell the caller
that the system has no resources (no data in the socket) to perform the requested action. In that case, it is the responsibility of
the caller may repeat the call until it succeeds.
For example, a
read() operation on a socket in non-blocking mode may return the number of read bytes or
a special return code -1 with errno set to
EWOULBLOCK/EAGAIN, meaning "not ready; try again later."
In a non-blocking asynchronous call, the calling function returns control to the caller immediately, reporting that the requested action was
started. The calling system will execute the caller's request using additional system resources/threads and will notify
the caller (by callback for example), when the result is ready for processing. For example, a Windows
aio_read() API returns immediately and initiates an internal system read operation.
Of the three approaches, this non-blocking asynchronous approach offers the best scalability and performance.
This article investigates different non-blocking I/O multiplexing mechanisms and proposes a single multi-platform design pattern/solution. We hope that this article will help developers of high performance TCP based servers to choose optimal design solution. We also compare the performance of Java, C# and C++ implementations of proposed and existing solutions. We will exclude the blocking approach from further discussion and comparison at all, as it the least effective approach for scalability and performance.