async.qbk 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. [/
  2. / Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  3. /
  4. / Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. /]
  7. [section:async The Proactor Design Pattern: Concurrency Without Threads]
  8. The Boost.Asio library offers side-by-side support for synchronous and asynchronous
  9. operations. The asynchronous support is based on the Proactor design pattern
  10. [link boost_asio.overview.core.async.references \[POSA2\]]. The advantages and
  11. disadvantages of this approach, when compared to a synchronous-only or Reactor
  12. approach, are outlined below.
  13. [heading Proactor and Boost.Asio]
  14. Let us examine how the Proactor design pattern is implemented in Boost.Asio,
  15. without reference to platform-specific details.
  16. [$boost_asio/proactor.png]
  17. [*Proactor design pattern (adapted from \[POSA2\])]
  18. [mdash] Asynchronous Operation
  19. [:Defines an operation that is executed asynchronously, such as an asynchronous
  20. read or write on a socket.]
  21. [mdash] Asynchronous Operation Processor
  22. [:Executes asynchronous operations and queues events on a completion event
  23. queue when operations complete. From a high-level point of view, internal
  24. services like `reactive_socket_service` are asynchronous operation processors.]
  25. [mdash] Completion Event Queue
  26. [:Buffers completion events until they are dequeued by an asynchronous event
  27. demultiplexer.]
  28. [mdash] Completion Handler
  29. [:Processes the result of an asynchronous operation. These are function
  30. objects, often created using `boost::bind`.]
  31. [mdash] Asynchronous Event Demultiplexer
  32. [:Blocks waiting for events to occur on the completion event queue, and returns
  33. a completed event to its caller.]
  34. [mdash] Proactor
  35. [:Calls the asynchronous event demultiplexer to dequeue events, and dispatches
  36. the completion handler (i.e. invokes the function object) associated with the
  37. event. This abstraction is represented by the `io_context` class.]
  38. [mdash] Initiator
  39. [:Application-specific code that starts asynchronous operations. The initiator
  40. interacts with an asynchronous operation processor via a high-level interface
  41. such as `basic_stream_socket`, which in turn delegates to a service like
  42. `reactive_socket_service`.]
  43. [heading Implementation Using Reactor]
  44. On many platforms, Boost.Asio implements the Proactor design pattern in terms
  45. of a Reactor, such as `select`, `epoll` or `kqueue`. This implementation
  46. approach corresponds to the Proactor design pattern as follows:
  47. [mdash] Asynchronous Operation Processor
  48. [:A reactor implemented using `select`, `epoll` or `kqueue`. When the reactor
  49. indicates that the resource is ready to perform the operation, the processor
  50. executes the asynchronous operation and enqueues the associated completion
  51. handler on the completion event queue.]
  52. [mdash] Completion Event Queue
  53. [:A linked list of completion handlers (i.e. function objects).]
  54. [mdash] Asynchronous Event Demultiplexer
  55. [:This is implemented by waiting on an event or condition variable until a
  56. completion handler is available in the completion event queue.]
  57. [heading Implementation Using Windows Overlapped I/O]
  58. On Windows NT, 2000 and XP, Boost.Asio takes advantage of overlapped I/O to
  59. provide an efficient implementation of the Proactor design pattern. This
  60. implementation approach corresponds to the Proactor design pattern as follows:
  61. [mdash] Asynchronous Operation Processor
  62. [:This is implemented by the operating system. Operations are initiated by
  63. calling an overlapped function such as `AcceptEx`.]
  64. [mdash] Completion Event Queue
  65. [:This is implemented by the operating system, and is associated with an I/O
  66. completion port. There is one I/O completion port for each `io_context`
  67. instance.]
  68. [mdash] Asynchronous Event Demultiplexer
  69. [:Called by Boost.Asio to dequeue events and their associated completion
  70. handlers.]
  71. [heading Advantages]
  72. [mdash] Portability.
  73. [:Many operating systems offer a native asynchronous I/O API (such as
  74. overlapped I/O on __Windows__) as the preferred option for developing high
  75. performance network applications. The library may be implemented in terms of
  76. native asynchronous I/O. However, if native support is not available, the
  77. library may also be implemented using synchronous event demultiplexors that
  78. typify the Reactor pattern, such as __POSIX__ `select()`.]
  79. [mdash] Decoupling threading from concurrency.
  80. [:Long-duration operations are performed asynchronously by the implementation
  81. on behalf of the application. Consequently applications do not need to spawn
  82. many threads in order to increase concurrency.]
  83. [mdash] Performance and scalability.
  84. [:Implementation strategies such as thread-per-connection (which a
  85. synchronous-only approach would require) can degrade system performance, due to
  86. increased context switching, synchronisation and data movement among CPUs. With
  87. asynchronous operations it is possible to avoid the cost of context switching
  88. by minimising the number of operating system threads [mdash] typically a
  89. limited resource [mdash] and only activating the logical threads of control
  90. that have events to process.]
  91. [mdash] Simplified application synchronisation.
  92. [:Asynchronous operation completion handlers can be written as though they
  93. exist in a single-threaded environment, and so application logic can be
  94. developed with little or no concern for synchronisation issues.]
  95. [mdash] Function composition.
  96. [:Function composition refers to the implementation of functions to provide a
  97. higher-level operation, such as sending a message in a particular format. Each
  98. function is implemented in terms of multiple calls to lower-level read or write
  99. operations.]
  100. [:For example, consider a protocol where each message consists of a
  101. fixed-length header followed by a variable length body, where the length of the
  102. body is specified in the header. A hypothetical read_message operation could be
  103. implemented using two lower-level reads, the first to receive the header and,
  104. once the length is known, the second to receive the body.]
  105. [:To compose functions in an asynchronous model, asynchronous operations can be
  106. chained together. That is, a completion handler for one operation can initiate
  107. the next. Starting the first call in the chain can be encapsulated so that the
  108. caller need not be aware that the higher-level operation is implemented as a
  109. chain of asynchronous operations.]
  110. [:The ability to compose new operations in this way simplifies the development
  111. of higher levels of abstraction above a networking library, such as functions
  112. to support a specific protocol.]
  113. [heading Disadvantages]
  114. [mdash] Program complexity.
  115. [:It is more difficult to develop applications using asynchronous mechanisms
  116. due to the separation in time and space between operation initiation and
  117. completion. Applications may also be harder to debug due to the inverted flow
  118. of control.]
  119. [mdash] Memory usage.
  120. [:Buffer space must be committed for the duration of a read or write operation,
  121. which may continue indefinitely, and a separate buffer is required for each
  122. concurrent operation. The Reactor pattern, on the other hand, does not require
  123. buffer space until a socket is ready for reading or writing.]
  124. [heading References]
  125. \[POSA2\] D. Schmidt et al, ['Pattern Oriented Software Architecture, Volume
  126. 2]. Wiley, 2000.
  127. [endsect]