I/O Event Handling Design Patterns

November 24, 2016
High Performance Server

[TOC]

Introduction

System I/O can be blocking, or non-blocking synchronous, or non-blocking asynchronous:

I/O multiplexing mechanisms rely on an event demultiplexor: dispatches I/O events from a limited number of sources to the appropriate read/write event handlers.

There are two non-blocking I/O multiplexing mechanisms: reactor && proactor.

Mechanism

  1. Reactor

    In the Reactor pattern, the event demultiplexor waits for events that indicate when a file descriptor or socket is ready for a read or write operation.

    Structure:

    • Request Event Dispatcher (synchronous event demultiplexer): uses an event loop to block on all resources, and dispatches resources from the demultiplexer to the associated event handler
    • Request Event Handler (user handler): performs the actual I/O operation, handles data, , declares renewed interest in I/O events, and returns control to the dispatcher

    Benific:

    • separates application specific code from the reactor implementation
    • allows for simple coarse-grain concurrency while not adding the complexity of multiple threads to the system

    Limitations:

    • more difficult to debug than a procedural pattern due to the inverted flow of control
    • by only calling event handlers synchronously, it limits maximum concurrency, especially on symmetric multiprocessing hardware
    • The scalability of the reactor pattern is limited by event handler and demultiplexer
  2. Proactor

    proactor

    In the Proactor pattern, the initiator (event demultiplexor) initiates asynchronous I/O operations. The I/O operation itself is performed by OS.

    A completion handler is called after the asynchronous part has terminated. The proactor pattern can be considered to be an asynchronous variant of the synchronous reactor pattern.

    The implementation of this classic asynchronous pattern is based on an asynchronous OS-level API, which is called it “system-level” or “true” async.

    Structure:

    • Proactive Initiator : initiates asynchronous I/O operations
    • Completion Event Dispatcher (event demultiplexor): waits for events that indicate the completion of the I/O operation, and forwards those events to the appropriate handlers
    • Completion Event Handler (user handler): handles the data from user defined buffer, starts a new asynchronous operation, and returns control to the dispatcher

Emulated Proactor Implementation

A solution to the challenge of designing a portable framework for the Proactor and Reactor I/O patterns: transform a Reactor demultiplexor I/O solution to an emulated async I/O by moving read/write operations from event handlers inside the demultiplexor (this is “emulated async” approach).

We simply shifted responsibilities between different actors. By adding functionality to the demultiplexor I/O pattern, we were able to convert the Reactor pattern to a Proactor pattern.

Structure:


Referenceļ¼š

Comparing Two High-Performance I/O Design Patterns

Reactor pattern

Proactor pattern

comments powered by Disqus