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