python.qbk 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. [section:python Python Bindings]
  2. [python]
  3. Boost.MPI provides an alternative MPI interface from the _Python_
  4. programming language via the `boost.mpi` module. The
  5. Boost.MPI Python bindings, built on top of the C++ Boost.MPI using the
  6. _BoostPython_ library, provide nearly all of the functionality of
  7. Boost.MPI within a dynamic, object-oriented language.
  8. The Boost.MPI Python module can be built and installed from the
  9. `libs/mpi/build` directory. Just follow the [link
  10. mpi.getting_started.config configuration] and [link mpi.getting_started.config.installation
  11. installation] instructions for the C++ Boost.MPI. Once you have
  12. installed the Python module, be sure that the installation location is
  13. in your `PYTHONPATH`.
  14. [section:quickstart Quickstart]
  15. [python]
  16. Getting started with the Boost.MPI Python module is as easy as
  17. importing `boost.mpi`. Our first "Hello, World!" program is
  18. just two lines long:
  19. import boost.mpi as mpi
  20. print "I am process %d of %d." % (mpi.rank, mpi.size)
  21. Go ahead and run this program with several processes. Be sure to
  22. invoke the `python` interpreter from `mpirun`, e.g.,
  23. [pre
  24. mpirun -np 5 python hello_world.py
  25. ]
  26. This will return output such as:
  27. [pre
  28. I am process 1 of 5.
  29. I am process 3 of 5.
  30. I am process 2 of 5.
  31. I am process 4 of 5.
  32. I am process 0 of 5.
  33. ]
  34. Point-to-point operations in Boost.MPI have nearly the same syntax in
  35. Python as in C++. We can write a simple two-process Python program
  36. that prints "Hello, world!" by transmitting Python strings:
  37. import boost.mpi as mpi
  38. if mpi.world.rank == 0:
  39. mpi.world.send(1, 0, 'Hello')
  40. msg = mpi.world.recv(1, 1)
  41. print msg,'!'
  42. else:
  43. msg = mpi.world.recv(0, 0)
  44. print (msg + ', '),
  45. mpi.world.send(0, 1, 'world')
  46. There are only a few notable differences between this Python code and
  47. the example [link mpi.tutorial.point_to_point in the C++
  48. tutorial]. First of all, we don't need to write any initialization
  49. code in Python: just loading the `boost.mpi` module makes the
  50. appropriate `MPI_Init` and `MPI_Finalize` calls. Second, we're passing
  51. Python objects from one process to another through MPI. Any Python
  52. object that can be pickled can be transmitted; the next section will
  53. describe in more detail how the Boost.MPI Python layer transmits
  54. objects. Finally, when we receive objects with `recv`, we don't need
  55. to specify the type because transmission of Python objects is
  56. polymorphic.
  57. When experimenting with Boost.MPI in Python, don't forget that help is
  58. always available via `pydoc`: just pass the name of the module or
  59. module entity on the command line (e.g., `pydoc
  60. boost.mpi.communicator`) to receive complete reference
  61. documentation. When in doubt, try it!
  62. [endsect:quickstart]
  63. [section:user_data Transmitting User-Defined Data]
  64. Boost.MPI can transmit user-defined data in several different ways.
  65. Most importantly, it can transmit arbitrary _Python_ objects by pickling
  66. them at the sender and unpickling them at the receiver, allowing
  67. arbitrarily complex Python data structures to interoperate with MPI.
  68. Boost.MPI also supports efficient serialization and transmission of
  69. C++ objects (that have been exposed to Python) through its C++
  70. interface. Any C++ type that provides (de-)serialization routines that
  71. meet the requirements of the Boost.Serialization library is eligible
  72. for this optimization, but the type must be registered in advance. To
  73. register a C++ type, invoke the C++ function [funcref
  74. boost::mpi::python::register_serialized
  75. register_serialized]. If your C++ types come from other Python modules
  76. (they probably will!), those modules will need to link against the
  77. `boost_mpi` and `boost_mpi_python` libraries as described in the [link
  78. mpi.getting_started.config.installation installation section]. Note that you do
  79. *not* need to link against the Boost.MPI Python extension module.
  80. Finally, Boost.MPI supports separation of the structure of an object
  81. from the data it stores, allowing the two pieces to be transmitted
  82. separately. This "skeleton/content" mechanism, described in more
  83. detail in a later section, is a communication optimization suitable
  84. for problems with fixed data structures whose internal data changes
  85. frequently.
  86. [endsect:user_data]
  87. [section:collectives Collectives]
  88. Boost.MPI supports all of the MPI collectives (`scatter`, `reduce`,
  89. `scan`, `broadcast`, etc.) for any type of data that can be
  90. transmitted with the point-to-point communication operations. For the
  91. MPI collectives that require a user-specified operation (e.g., `reduce`
  92. and `scan`), the operation can be an arbitrary Python function. For
  93. instance, one could concatenate strings with `all_reduce`:
  94. mpi.all_reduce(my_string, lambda x,y: x + y)
  95. The following module-level functions implement MPI collectives:
  96. all_gather Gather the values from all processes.
  97. all_reduce Combine the results from all processes.
  98. all_to_all Every process sends data to every other process.
  99. broadcast Broadcast data from one process to all other processes.
  100. gather Gather the values from all processes to the root.
  101. reduce Combine the results from all processes to the root.
  102. scan Prefix reduction of the values from all processes.
  103. scatter Scatter the values stored at the root to all processes.
  104. [endsect:collectives]
  105. [section:skeleton_content Skeleton/Content Mechanism]
  106. Boost.MPI provides a skeleton/content mechanism that allows the
  107. transfer of large data structures to be split into two separate stages,
  108. with the skeleton (or, "shape") of the data structure sent first and
  109. the content (or, "data") of the data structure sent later, potentially
  110. several times, so long as the structure has not changed since the
  111. skeleton was transferred. The skeleton/content mechanism can improve
  112. performance when the data structure is large and its shape is fixed,
  113. because while the skeleton requires serialization (it has an unknown
  114. size), the content transfer is fixed-size and can be done without
  115. extra copies.
  116. To use the skeleton/content mechanism from Python, you must first
  117. register the type of your data structure with the skeleton/content
  118. mechanism *from C++*. The registration function is [funcref
  119. boost::mpi::python::register_skeleton_and_content
  120. register_skeleton_and_content] and resides in the [headerref
  121. boost/mpi/python.hpp <boost/mpi/python.hpp>] header.
  122. Once you have registered your C++ data structures, you can extract
  123. the skeleton for an instance of that data structure with `skeleton()`.
  124. The resulting `skeleton_proxy` can be transmitted via the normal send
  125. routine, e.g.,
  126. mpi.world.send(1, 0, skeleton(my_data_structure))
  127. `skeleton_proxy` objects can be received on the other end via `recv()`,
  128. which stores a newly-created instance of your data structure with the
  129. same "shape" as the sender in its `"object"` attribute:
  130. shape = mpi.world.recv(0, 0)
  131. my_data_structure = shape.object
  132. Once the skeleton has been transmitted, the content (accessed via
  133. `get_content`) can be transmitted in much the same way. Note, however,
  134. that the receiver also specifies `get_content(my_data_structure)` in its
  135. call to receive:
  136. if mpi.rank == 0:
  137. mpi.world.send(1, 0, get_content(my_data_structure))
  138. else:
  139. mpi.world.recv(0, 0, get_content(my_data_structure))
  140. Of course, this transmission of content can occur repeatedly, if the
  141. values in the data structure--but not its shape--changes.
  142. The skeleton/content mechanism is a structured way to exploit the
  143. interaction between custom-built MPI datatypes and `MPI_BOTTOM`, to
  144. eliminate extra buffer copies.
  145. [endsect:skeleton_content]
  146. [section:compatibility C++/Python MPI Compatibility]
  147. Boost.MPI is a C++ library whose facilities have been exposed to Python
  148. via the Boost.Python library. Since the Boost.MPI Python bindings are
  149. build directly on top of the C++ library, and nearly every feature of
  150. C++ library is available in Python, hybrid C++/Python programs using
  151. Boost.MPI can interact, e.g., sending a value from Python but receiving
  152. that value in C++ (or vice versa). However, doing so requires some
  153. care. Because Python objects are dynamically typed, Boost.MPI transfers
  154. type information along with the serialized form of the object, so that
  155. the object can be received even when its type is not known. This
  156. mechanism differs from its C++ counterpart, where the static types of
  157. transmitted values are always known.
  158. The only way to communicate between the C++ and Python views on
  159. Boost.MPI is to traffic entirely in Python objects. For Python, this
  160. is the normal state of affairs, so nothing will change. For C++, this
  161. means sending and receiving values of type `boost::python::object`,
  162. from the _BoostPython_ library. For instance, say we want to transmit
  163. an integer value from Python:
  164. comm.send(1, 0, 17)
  165. In C++, we would receive that value into a Python object and then
  166. `extract` an integer value:
  167. [c++]
  168. boost::python::object value;
  169. comm.recv(0, 0, value);
  170. int int_value = boost::python::extract<int>(value);
  171. In the future, Boost.MPI will be extended to allow improved
  172. interoperability with the C++ Boost.MPI and the C MPI bindings.
  173. [endsect:compatibility]
  174. [section:reference Reference]
  175. The Boost.MPI Python module, `boost.mpi`, has its own
  176. [@boost.mpi.html reference documentation], which is also
  177. available using `pydoc` (from the command line) or
  178. `help(boost.mpi)` (from the Python interpreter).
  179. [endsect:reference]
  180. [endsect:python]