http://www.artima.com/articles/io_design_patterns3.html
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.
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.
a non-blocking synchronous call returns control to the caller immediately.
it is the responsibility of the caller may repeat the call until it succeeds.
In a non-blocking asynchronous call, the calling function returns control to the caller immediately, reporting that the requested action was started.
Of the three approaches, this non-blocking asynchronous approach offers the best scalability and performance.
The Reactor patterns involve synchronous I/O, whereas the Proactor pattern involves asynchronous I/O.
Standard/classic Reactor:
- Step 1) wait for event (Reactor job)
- Step 2) dispatch "Ready-to-Read" event to user handler ( Reactor job)
- Step 3) read data (user handler job)
- Step 4) process data ( user handler job)
Proposed emulated Proactor:
- Step 1) wait for event (Proactor job)
- Step 2) read data (now Proactor job)
- Step 3) dispatch "Read-Completed" event to user handler (Proactor job)
- Step 4) process data (user handler job)
It internally implements three engines (POSIX AIO, SUN AIO and Emulated AIO) and hides
six different waiting strategies, based on
an asynchronous kernel API (for POSIX- this is not efficient right now due to internal POSIX AIO API problems)
and synchronous Unix
select()
,
poll()
,
/dev/poll (Solaris 5.8+),
port_get
(Solaris 5.10),
RealTime (RT) signals (Linux 2.4+),
epoll (Linux 2.6),
k-queue (FreeBSD) APIs.
the user can opt for an emulated async solutions built on different sync waiting strategies