Show More
@@ -0,0 +1,116 b'' | |||||
|
1 | .. _parallel_asyncresult: | |||
|
2 | ||||
|
3 | ====================== | |||
|
4 | The AsyncResult object | |||
|
5 | ====================== | |||
|
6 | ||||
|
7 | In non-blocking mode, :meth:`apply` submits the command to be executed and | |||
|
8 | then returns a :class:`~.AsyncResult` object immediately. The | |||
|
9 | AsyncResult object gives you a way of getting a result at a later | |||
|
10 | time through its :meth:`get` method, but it also collects metadata | |||
|
11 | on execution. | |||
|
12 | ||||
|
13 | ||||
|
14 | Beyond multiprocessing's AsyncResult | |||
|
15 | ==================================== | |||
|
16 | ||||
|
17 | .. Note:: | |||
|
18 | ||||
|
19 | The :class:`~.AsyncResult` object provides a superset of the interface in | |||
|
20 | :py:class:`multiprocessing.pool.AsyncResult`. See the | |||
|
21 | `official Python documentation <http://docs.python.org/library/multiprocessing#multiprocessing.pool.AsyncResult>`_ | |||
|
22 | for more on the basics of this interface. | |||
|
23 | ||||
|
24 | Our AsyncResult objects add a number of convenient features for working with | |||
|
25 | parallel results, beyond what is provided by the original AsyncResult. | |||
|
26 | ||||
|
27 | ||||
|
28 | get_dict | |||
|
29 | -------- | |||
|
30 | ||||
|
31 | First, is :meth:`.AsyncResult.get_dict`, which pulls results as a dictionary | |||
|
32 | keyed by engine_id, rather than a flat list. This is useful for quickly | |||
|
33 | coordinating or distributing information about all of the engines. | |||
|
34 | ||||
|
35 | As an example, here is a quick call that gives every engine a dict showing | |||
|
36 | the PID of every other engine: | |||
|
37 | ||||
|
38 | .. sourcecode:: ipython | |||
|
39 | ||||
|
40 | In [10]: ar = rc[:].apply_async(os.getpid) | |||
|
41 | In [11]: pids = ar.get_dict() | |||
|
42 | In [12]: rc[:]['pid_map'] = pids | |||
|
43 | ||||
|
44 | This trick is particularly useful when setting up inter-engine communication, | |||
|
45 | as in IPython's :file:`examples/parallel/interengine` examples. | |||
|
46 | ||||
|
47 | ||||
|
48 | Metadata | |||
|
49 | ======== | |||
|
50 | ||||
|
51 | IPython.parallel tracks some metadata about the tasks, which is stored | |||
|
52 | in the :attr:`.Client.metadata` dict. The AsyncResult object gives you an | |||
|
53 | interface for this information as well, including timestamps stdout/err, | |||
|
54 | and engine IDs. | |||
|
55 | ||||
|
56 | ||||
|
57 | Timing | |||
|
58 | ------ | |||
|
59 | ||||
|
60 | IPython tracks various timestamps as :py:class:`.datetime` objects, | |||
|
61 | and the AsyncResult object has a few properties that turn these into useful | |||
|
62 | times (in seconds as floats). | |||
|
63 | ||||
|
64 | For use while the tasks are still pending: | |||
|
65 | ||||
|
66 | * :attr:`ar.elapsed` is just the elapsed seconds since submission, for use | |||
|
67 | before the AsyncResult is complete. | |||
|
68 | * :attr:`ar.progress` is the number of tasks that have completed. Fractional progress | |||
|
69 | would be:: | |||
|
70 | ||||
|
71 | 1.0 * ar.progress / len(ar) | |||
|
72 | ||||
|
73 | * :meth:`AsyncResult.wait_interactive` will wait for the result to finish, but | |||
|
74 | print out status updates on progress and elapsed time while it waits. | |||
|
75 | ||||
|
76 | For use after the tasks are done: | |||
|
77 | ||||
|
78 | * :attr:`ar.serial_time` is the sum of the computation time of all of the tasks | |||
|
79 | done in parallel. | |||
|
80 | * :attr:`ar.wall_time` is the time between the first task submitted and last result | |||
|
81 | received. This is the actual cost of computation, including IPython overhead. | |||
|
82 | ||||
|
83 | ||||
|
84 | .. note:: | |||
|
85 | ||||
|
86 | wall_time is only precise if the Client is waiting for results when | |||
|
87 | the task finished, because the `received` timestamp is made when the result is | |||
|
88 | unpacked by the Client, triggered by the :meth:`~Client.spin` call. If you | |||
|
89 | are doing work in the Client, and not waiting/spinning, then `received` might | |||
|
90 | be artificially high. | |||
|
91 | ||||
|
92 | An often interesting metric is the time it actually cost to do the work in parallel | |||
|
93 | relative to the serial computation, and this can be given simply with | |||
|
94 | ||||
|
95 | .. sourcecode:: python | |||
|
96 | ||||
|
97 | speedup = ar.serial_time / ar.wall_time | |||
|
98 | ||||
|
99 | ||||
|
100 | Map results are iterable! | |||
|
101 | ========================= | |||
|
102 | ||||
|
103 | When an AsyncResult object has multiple results (e.g. the :class:`~AsyncMapResult` | |||
|
104 | object), you can actually iterate through them, and act on the results as they arrive: | |||
|
105 | ||||
|
106 | .. literalinclude:: ../../examples/parallel/itermapresult.py | |||
|
107 | :language: python | |||
|
108 | :lines: 20-66 | |||
|
109 | ||||
|
110 | .. seealso:: | |||
|
111 | ||||
|
112 | When AsyncResult or the AsyncMapResult don't provide what you need (for instance, | |||
|
113 | handling individual results as they arrive, but with metadata), you can always | |||
|
114 | just split the original result's ``msg_ids`` attribute, and handle them as you like. | |||
|
115 | ||||
|
116 | For an example of this, see :file:`docs/examples/parallel/customresult.py` |
@@ -11,6 +11,7 b' Using IPython for parallel computing' | |||||
11 | parallel_process.txt |
|
11 | parallel_process.txt | |
12 | parallel_multiengine.txt |
|
12 | parallel_multiengine.txt | |
13 | parallel_task.txt |
|
13 | parallel_task.txt | |
|
14 | asyncresult.txt | |||
14 | parallel_mpi.txt |
|
15 | parallel_mpi.txt | |
15 | parallel_db.txt |
|
16 | parallel_db.txt | |
16 | parallel_security.txt |
|
17 | parallel_security.txt |
@@ -275,13 +275,9 b' then returns a :class:`AsyncResult` object immediately. The' | |||||
275 | :class:`AsyncResult` object gives you a way of getting a result at a later |
|
275 | :class:`AsyncResult` object gives you a way of getting a result at a later | |
276 | time through its :meth:`get` method. |
|
276 | time through its :meth:`get` method. | |
277 |
|
277 | |||
278 | .. Note:: |
|
278 | .. seealso:: | |
279 |
|
||||
280 | The :class:`AsyncResult` object provides a superset of the interface in |
|
|||
281 | :py:class:`multiprocessing.pool.AsyncResult`. See the |
|
|||
282 | `official Python documentation <http://docs.python.org/library/multiprocessing#multiprocessing.pool.AsyncResult>`_ |
|
|||
283 | for more. |
|
|||
284 |
|
279 | |||
|
280 | Docs on the :ref:`AsyncResult <parallel_asyncresult>` object. | |||
285 |
|
281 | |||
286 | This allows you to quickly submit long running commands without blocking your |
|
282 | This allows you to quickly submit long running commands without blocking your | |
287 | local Python/IPython session: |
|
283 | local Python/IPython session: |
@@ -111,27 +111,6 b' that turns any Python function into a parallel function:' | |||||
111 | In [11]: f.map(range(32)) # this is done in parallel |
|
111 | In [11]: f.map(range(32)) # this is done in parallel | |
112 | Out[11]: [0.0,10.0,160.0,...] |
|
112 | Out[11]: [0.0,10.0,160.0,...] | |
113 |
|
113 | |||
114 | .. _parallel_taskmap: |
|
|||
115 |
|
||||
116 | Map results are iterable! |
|
|||
117 | ------------------------- |
|
|||
118 |
|
||||
119 | When an AsyncResult object actually maps multiple results (e.g. the :class:`~AsyncMapResult` |
|
|||
120 | object), you can actually iterate through them, and act on the results as they arrive: |
|
|||
121 |
|
||||
122 | .. literalinclude:: ../../examples/parallel/itermapresult.py |
|
|||
123 | :language: python |
|
|||
124 | :lines: 9-34 |
|
|||
125 |
|
||||
126 | .. seealso:: |
|
|||
127 |
|
||||
128 | When AsyncResult or the AsyncMapResult don't provide what you need (for instance, |
|
|||
129 | handling individual results as they arrive, but with metadata), you can always |
|
|||
130 | just split the original result's ``msg_ids`` attribute, and handle them as you like. |
|
|||
131 |
|
||||
132 | For an example of this, see :file:`docs/examples/parallel/customresult.py` |
|
|||
133 |
|
||||
134 |
|
||||
135 | .. _parallel_dependencies: |
|
114 | .. _parallel_dependencies: | |
136 |
|
115 | |||
137 | Dependencies |
|
116 | Dependencies |
General Comments 0
You need to be logged in to leave comments.
Login now