##// END OF EJS Templates
Fix up some problems with parallel docs
Thomas Kluyver -
Show More
@@ -1,385 +1,387 b''
1 .. _parallel_magics:
1 .. _parallel_magics:
2
2
3 =======================
3 =======================
4 Parallel Magic Commands
4 Parallel Magic Commands
5 =======================
5 =======================
6
6
7 We provide a few IPython magic commands
7 We provide a few IPython magic commands
8 that make it a bit more pleasant to execute Python commands on the engines interactively.
8 that make it a bit more pleasant to execute Python commands on the engines interactively.
9 These are mainly shortcuts to :meth:`.DirectView.execute`
9 These are mainly shortcuts to :meth:`.DirectView.execute`
10 and :meth:`.AsyncResult.display_outputs` methods repsectively.
10 and :meth:`.AsyncResult.display_outputs` methods repsectively.
11
11
12 These magics will automatically become available when you create a Client:
12 These magics will automatically become available when you create a Client:
13
13
14 .. sourcecode:: ipython
14 .. sourcecode:: ipython
15
15
16 In [2]: rc = parallel.Client()
16 In [2]: rc = parallel.Client()
17
17
18 The initially active View will have attributes ``targets='all', block=True``,
18 The initially active View will have attributes ``targets='all', block=True``,
19 which is a blocking view of all engines, evaluated at request time
19 which is a blocking view of all engines, evaluated at request time
20 (adding/removing engines will change where this view's tasks will run).
20 (adding/removing engines will change where this view's tasks will run).
21
21
22 The Magics
22 The Magics
23 ==========
23 ==========
24
24
25 %px
25 %px
26 ---
26 ---
27
27
28 The %px magic executes a single Python command on the engines
28 The %px magic executes a single Python command on the engines
29 specified by the :attr:`targets` attribute of the :class:`DirectView` instance:
29 specified by the :attr:`targets` attribute of the :class:`DirectView` instance:
30
30
31 .. sourcecode:: ipython
31 .. sourcecode:: ipython
32
32
33 # import numpy here and everywhere
33 # import numpy here and everywhere
34 In [25]: with rc[:].sync_imports():
34 In [25]: with rc[:].sync_imports():
35 ....: import numpy
35 ....: import numpy
36 importing numpy on engine(s)
36 importing numpy on engine(s)
37
37
38 In [27]: %px a = numpy.random.rand(2,2)
38 In [27]: %px a = numpy.random.rand(2,2)
39 Parallel execution on engines: [0, 1, 2, 3]
39 Parallel execution on engines: [0, 1, 2, 3]
40
40
41 In [28]: %px numpy.linalg.eigvals(a)
41 In [28]: %px numpy.linalg.eigvals(a)
42 Parallel execution on engines: [0, 1, 2, 3]
42 Parallel execution on engines: [0, 1, 2, 3]
43 Out [0:68]: array([ 0.77120707, -0.19448286])
43 Out [0:68]: array([ 0.77120707, -0.19448286])
44 Out [1:68]: array([ 1.10815921, 0.05110369])
44 Out [1:68]: array([ 1.10815921, 0.05110369])
45 Out [2:68]: array([ 0.74625527, -0.37475081])
45 Out [2:68]: array([ 0.74625527, -0.37475081])
46 Out [3:68]: array([ 0.72931905, 0.07159743])
46 Out [3:68]: array([ 0.72931905, 0.07159743])
47
47
48 In [29]: %px print 'hi'
48 In [29]: %px print 'hi'
49 Parallel execution on engine(s): all
49 Parallel execution on engine(s): all
50 [stdout:0] hi
50 [stdout:0] hi
51 [stdout:1] hi
51 [stdout:1] hi
52 [stdout:2] hi
52 [stdout:2] hi
53 [stdout:3] hi
53 [stdout:3] hi
54
54
55
55
56 Since engines are IPython as well, you can even run magics remotely:
56 Since engines are IPython as well, you can even run magics remotely:
57
57
58 .. sourcecode:: ipython
58 .. sourcecode:: ipython
59
59
60 In [28]: %px %pylab inline
60 In [28]: %px %pylab inline
61 Parallel execution on engine(s): all
61 Parallel execution on engine(s): all
62 [stdout:0]
62 [stdout:0]
63 Populating the interactive namespace from numpy and matplotlib
63 Populating the interactive namespace from numpy and matplotlib
64 [stdout:1]
64 [stdout:1]
65 Populating the interactive namespace from numpy and matplotlib
65 Populating the interactive namespace from numpy and matplotlib
66 [stdout:2]
66 [stdout:2]
67 Populating the interactive namespace from numpy and matplotlib
67 Populating the interactive namespace from numpy and matplotlib
68 [stdout:3]
68 [stdout:3]
69 Populating the interactive namespace from numpy and matplotlib
69 Populating the interactive namespace from numpy and matplotlib
70
70
71 And once in pylab mode with the inline backend,
71 And once in pylab mode with the inline backend,
72 you can make plots and they will be displayed in your frontend
72 you can make plots and they will be displayed in your frontend
73 if it suports the inline figures (e.g. notebook or qtconsole):
73 if it suports the inline figures (e.g. notebook or qtconsole):
74
74
75 .. sourcecode:: ipython
75 .. sourcecode:: ipython
76
76
77 In [40]: %px plot(rand(100))
77 In [40]: %px plot(rand(100))
78 Parallel execution on engine(s): all
78 Parallel execution on engine(s): all
79 <plot0>
79 <plot0>
80 <plot1>
80 <plot1>
81 <plot2>
81 <plot2>
82 <plot3>
82 <plot3>
83 Out[0:79]: [<matplotlib.lines.Line2D at 0x10a6286d0>]
83 Out[0:79]: [<matplotlib.lines.Line2D at 0x10a6286d0>]
84 Out[1:79]: [<matplotlib.lines.Line2D at 0x10b9476d0>]
84 Out[1:79]: [<matplotlib.lines.Line2D at 0x10b9476d0>]
85 Out[2:79]: [<matplotlib.lines.Line2D at 0x110652750>]
85 Out[2:79]: [<matplotlib.lines.Line2D at 0x110652750>]
86 Out[3:79]: [<matplotlib.lines.Line2D at 0x10c6566d0>]
86 Out[3:79]: [<matplotlib.lines.Line2D at 0x10c6566d0>]
87
87
88
88
89 %%px Cell Magic
89 %%px Cell Magic
90 ---------------
90 ---------------
91
91
92 %%px can be used as a Cell Magic, which accepts some arguments for controlling
92 %%px can be used as a Cell Magic, which accepts some arguments for controlling
93 the execution.
93 the execution.
94
94
95
95
96 Targets and Blocking
96 Targets and Blocking
97 ********************
97 ********************
98
98
99 %%px accepts ``--targets`` for controlling which engines on which to run,
99 %%px accepts ``--targets`` for controlling which engines on which to run,
100 and ``--[no]block`` for specifying the blocking behavior of this cell,
100 and ``--[no]block`` for specifying the blocking behavior of this cell,
101 independent of the defaults for the View.
101 independent of the defaults for the View.
102
102
103 .. sourcecode:: ipython
103 .. sourcecode:: ipython
104
104
105 In [6]: %%px --targets ::2
105 In [6]: %%px --targets ::2
106 ...: print "I am even"
106 ...: print "I am even"
107 ...:
107 ...:
108 Parallel execution on engine(s): [0, 2]
108 Parallel execution on engine(s): [0, 2]
109 [stdout:0] I am even
109 [stdout:0] I am even
110 [stdout:2] I am even
110 [stdout:2] I am even
111
111
112 In [7]: %%px --targets 1
112 In [7]: %%px --targets 1
113 ...: print "I am number 1"
113 ...: print "I am number 1"
114 ...:
114 ...:
115 Parallel execution on engine(s): 1
115 Parallel execution on engine(s): 1
116 I am number 1
116 I am number 1
117
117
118 In [8]: %%px
118 In [8]: %%px
119 ...: print "still 'all' by default"
119 ...: print "still 'all' by default"
120 ...:
120 ...:
121 Parallel execution on engine(s): all
121 Parallel execution on engine(s): all
122 [stdout:0] still 'all' by default
122 [stdout:0] still 'all' by default
123 [stdout:1] still 'all' by default
123 [stdout:1] still 'all' by default
124 [stdout:2] still 'all' by default
124 [stdout:2] still 'all' by default
125 [stdout:3] still 'all' by default
125 [stdout:3] still 'all' by default
126
126
127 In [9]: %%px --noblock
127 In [9]: %%px --noblock
128 ...: import time
128 ...: import time
129 ...: time.sleep(1)
129 ...: time.sleep(1)
130 ...: time.time()
130 ...: time.time()
131 ...:
131 ...:
132 Async parallel execution on engine(s): all
132 Async parallel execution on engine(s): all
133 Out[9]: <AsyncResult: execute>
133 Out[9]: <AsyncResult: execute>
134
134
135 In [10]: %pxresult
135 In [10]: %pxresult
136 Out[0:12]: 1339454561.069116
136 Out[0:12]: 1339454561.069116
137 Out[1:10]: 1339454561.076752
137 Out[1:10]: 1339454561.076752
138 Out[2:12]: 1339454561.072837
138 Out[2:12]: 1339454561.072837
139 Out[3:10]: 1339454561.066665
139 Out[3:10]: 1339454561.066665
140
140
141
141
142 .. seealso::
142 .. seealso::
143
143
144 :ref:`%pxconfig` accepts these same arguments for changing the *default*
144 :ref:`pxconfig` accepts these same arguments for changing the *default*
145 values of targets/blocking for the active View.
145 values of targets/blocking for the active View.
146
146
147
147
148 Output Display
148 Output Display
149 **************
149 **************
150
150
151
151
152 %%px also accepts a ``--group-outputs`` argument,
152 %%px also accepts a ``--group-outputs`` argument,
153 which adjusts how the outputs of multiple engines are presented.
153 which adjusts how the outputs of multiple engines are presented.
154
154
155 .. seealso::
155 .. seealso::
156
156
157 :meth:`.AsyncResult.display_outputs` for the grouping options.
157 :meth:`.AsyncResult.display_outputs` for the grouping options.
158
158
159 .. sourcecode:: ipython
159 .. sourcecode:: ipython
160
160
161 In [50]: %%px --block --group-outputs=engine
161 In [50]: %%px --block --group-outputs=engine
162 ....: import numpy as np
162 ....: import numpy as np
163 ....: A = np.random.random((2,2))
163 ....: A = np.random.random((2,2))
164 ....: ev = numpy.linalg.eigvals(A)
164 ....: ev = numpy.linalg.eigvals(A)
165 ....: print ev
165 ....: print ev
166 ....: ev.max()
166 ....: ev.max()
167 ....:
167 ....:
168 Parallel execution on engine(s): all
168 Parallel execution on engine(s): all
169 [stdout:0] [ 0.60640442 0.95919621]
169 [stdout:0] [ 0.60640442 0.95919621]
170 Out [0:73]: 0.9591962130899806
170 Out [0:73]: 0.9591962130899806
171 [stdout:1] [ 0.38501813 1.29430871]
171 [stdout:1] [ 0.38501813 1.29430871]
172 Out [1:73]: 1.2943087091452372
172 Out [1:73]: 1.2943087091452372
173 [stdout:2] [-0.85925141 0.9387692 ]
173 [stdout:2] [-0.85925141 0.9387692 ]
174 Out [2:73]: 0.93876920456230284
174 Out [2:73]: 0.93876920456230284
175 [stdout:3] [ 0.37998269 1.24218246]
175 [stdout:3] [ 0.37998269 1.24218246]
176 Out [3:73]: 1.2421824618493817
176 Out [3:73]: 1.2421824618493817
177
177
178
178
179 %pxresult
179 %pxresult
180 ---------
180 ---------
181
181
182 If you are using %px in non-blocking mode, you won't get output.
182 If you are using %px in non-blocking mode, you won't get output.
183 You can use %pxresult to display the outputs of the latest command,
183 You can use %pxresult to display the outputs of the latest command,
184 just as is done when %px is blocking:
184 just as is done when %px is blocking:
185
185
186 .. sourcecode:: ipython
186 .. sourcecode:: ipython
187
187
188 In [39]: dv.block = False
188 In [39]: dv.block = False
189
189
190 In [40]: %px print 'hi'
190 In [40]: %px print 'hi'
191 Async parallel execution on engine(s): all
191 Async parallel execution on engine(s): all
192
192
193 In [41]: %pxresult
193 In [41]: %pxresult
194 [stdout:0] hi
194 [stdout:0] hi
195 [stdout:1] hi
195 [stdout:1] hi
196 [stdout:2] hi
196 [stdout:2] hi
197 [stdout:3] hi
197 [stdout:3] hi
198
198
199 %pxresult simply calls :meth:`.AsyncResult.display_outputs` on the most recent request.
199 %pxresult simply calls :meth:`.AsyncResult.display_outputs` on the most recent request.
200 It accepts the same output-grouping arguments as %%px, so you can use it to view
200 It accepts the same output-grouping arguments as %%px, so you can use it to view
201 a result in different ways.
201 a result in different ways.
202
202
203
203
204 %autopx
204 %autopx
205 -------
205 -------
206
206
207 The %autopx magic switches to a mode where everything you type is executed
207 The %autopx magic switches to a mode where everything you type is executed
208 on the engines until you do %autopx again.
208 on the engines until you do %autopx again.
209
209
210 .. sourcecode:: ipython
210 .. sourcecode:: ipython
211
211
212 In [30]: dv.block=True
212 In [30]: dv.block=True
213
213
214 In [31]: %autopx
214 In [31]: %autopx
215 %autopx enabled
215 %autopx enabled
216
216
217 In [32]: max_evals = []
217 In [32]: max_evals = []
218
218
219 In [33]: for i in range(100):
219 In [33]: for i in range(100):
220 ....: a = numpy.random.rand(10,10)
220 ....: a = numpy.random.rand(10,10)
221 ....: a = a+a.transpose()
221 ....: a = a+a.transpose()
222 ....: evals = numpy.linalg.eigvals(a)
222 ....: evals = numpy.linalg.eigvals(a)
223 ....: max_evals.append(evals[0].real)
223 ....: max_evals.append(evals[0].real)
224 ....:
224 ....:
225
225
226 In [34]: print "Average max eigenvalue is: %f" % (sum(max_evals)/len(max_evals))
226 In [34]: print "Average max eigenvalue is: %f" % (sum(max_evals)/len(max_evals))
227 [stdout:0] Average max eigenvalue is: 10.193101
227 [stdout:0] Average max eigenvalue is: 10.193101
228 [stdout:1] Average max eigenvalue is: 10.064508
228 [stdout:1] Average max eigenvalue is: 10.064508
229 [stdout:2] Average max eigenvalue is: 10.055724
229 [stdout:2] Average max eigenvalue is: 10.055724
230 [stdout:3] Average max eigenvalue is: 10.086876
230 [stdout:3] Average max eigenvalue is: 10.086876
231
231
232 In [35]: %autopx
232 In [35]: %autopx
233 Auto Parallel Disabled
233 Auto Parallel Disabled
234
234
235 .. _pxconfig:
236
235 %pxconfig
237 %pxconfig
236 ---------
238 ---------
237
239
238 The default targets and blocking behavior for the magics are governed by the :attr:`block`
240 The default targets and blocking behavior for the magics are governed by the :attr:`block`
239 and :attr:`targets` attribute of the active View. If you have a handle for the view,
241 and :attr:`targets` attribute of the active View. If you have a handle for the view,
240 you can set these attributes directly, but if you don't, you can change them with
242 you can set these attributes directly, but if you don't, you can change them with
241 the %pxconfig magic:
243 the %pxconfig magic:
242
244
243 .. sourcecode:: ipython
245 .. sourcecode:: ipython
244
246
245 In [3]: %pxconfig --block
247 In [3]: %pxconfig --block
246
248
247 In [5]: %px print 'hi'
249 In [5]: %px print 'hi'
248 Parallel execution on engine(s): all
250 Parallel execution on engine(s): all
249 [stdout:0] hi
251 [stdout:0] hi
250 [stdout:1] hi
252 [stdout:1] hi
251 [stdout:2] hi
253 [stdout:2] hi
252 [stdout:3] hi
254 [stdout:3] hi
253
255
254 In [6]: %pxconfig --targets ::2
256 In [6]: %pxconfig --targets ::2
255
257
256 In [7]: %px print 'hi'
258 In [7]: %px print 'hi'
257 Parallel execution on engine(s): [0, 2]
259 Parallel execution on engine(s): [0, 2]
258 [stdout:0] hi
260 [stdout:0] hi
259 [stdout:2] hi
261 [stdout:2] hi
260
262
261 In [8]: %pxconfig --noblock
263 In [8]: %pxconfig --noblock
262
264
263 In [9]: %px print 'are you there?'
265 In [9]: %px print 'are you there?'
264 Async parallel execution on engine(s): [0, 2]
266 Async parallel execution on engine(s): [0, 2]
265 Out[9]: <AsyncResult: execute>
267 Out[9]: <AsyncResult: execute>
266
268
267 In [10]: %pxresult
269 In [10]: %pxresult
268 [stdout:0] are you there?
270 [stdout:0] are you there?
269 [stdout:2] are you there?
271 [stdout:2] are you there?
270
272
271
273
272 Multiple Active Views
274 Multiple Active Views
273 =====================
275 =====================
274
276
275 The parallel magics are associated with a particular :class:`~.DirectView` object.
277 The parallel magics are associated with a particular :class:`~.DirectView` object.
276 You can change the active view by calling the :meth:`~.DirectView.activate` method
278 You can change the active view by calling the :meth:`~.DirectView.activate` method
277 on any view.
279 on any view.
278
280
279 .. sourcecode:: ipython
281 .. sourcecode:: ipython
280
282
281 In [11]: even = rc[::2]
283 In [11]: even = rc[::2]
282
284
283 In [12]: even.activate()
285 In [12]: even.activate()
284
286
285 In [13]: %px print 'hi'
287 In [13]: %px print 'hi'
286 Async parallel execution on engine(s): [0, 2]
288 Async parallel execution on engine(s): [0, 2]
287 Out[13]: <AsyncResult: execute>
289 Out[13]: <AsyncResult: execute>
288
290
289 In [14]: even.block = True
291 In [14]: even.block = True
290
292
291 In [15]: %px print 'hi'
293 In [15]: %px print 'hi'
292 Parallel execution on engine(s): [0, 2]
294 Parallel execution on engine(s): [0, 2]
293 [stdout:0] hi
295 [stdout:0] hi
294 [stdout:2] hi
296 [stdout:2] hi
295
297
296 When activating a View, you can also specify a *suffix*, so that a whole different
298 When activating a View, you can also specify a *suffix*, so that a whole different
297 set of magics are associated with that view, without replacing the existing ones.
299 set of magics are associated with that view, without replacing the existing ones.
298
300
299 .. sourcecode:: ipython
301 .. sourcecode:: ipython
300
302
301 # restore the original DirecView to the base %px magics
303 # restore the original DirecView to the base %px magics
302 In [16]: rc.activate()
304 In [16]: rc.activate()
303 Out[16]: <DirectView all>
305 Out[16]: <DirectView all>
304
306
305 In [17]: even.activate('_even')
307 In [17]: even.activate('_even')
306
308
307 In [18]: %px print 'hi all'
309 In [18]: %px print 'hi all'
308 Parallel execution on engine(s): all
310 Parallel execution on engine(s): all
309 [stdout:0] hi all
311 [stdout:0] hi all
310 [stdout:1] hi all
312 [stdout:1] hi all
311 [stdout:2] hi all
313 [stdout:2] hi all
312 [stdout:3] hi all
314 [stdout:3] hi all
313
315
314 In [19]: %px_even print "We aren't odd!"
316 In [19]: %px_even print "We aren't odd!"
315 Parallel execution on engine(s): [0, 2]
317 Parallel execution on engine(s): [0, 2]
316 [stdout:0] We aren't odd!
318 [stdout:0] We aren't odd!
317 [stdout:2] We aren't odd!
319 [stdout:2] We aren't odd!
318
320
319 This suffix is applied to the end of all magics, e.g. %autopx_even, %pxresult_even, etc.
321 This suffix is applied to the end of all magics, e.g. %autopx_even, %pxresult_even, etc.
320
322
321 For convenience, the :class:`~.Client` has a :meth:`~.Client.activate` method as well,
323 For convenience, the :class:`~.Client` has a :meth:`~.Client.activate` method as well,
322 which creates a DirectView with block=True, activates it, and returns the new View.
324 which creates a DirectView with block=True, activates it, and returns the new View.
323
325
324 The initial magics registered when you create a client are the result of a call to
326 The initial magics registered when you create a client are the result of a call to
325 :meth:`rc.activate` with default args.
327 :meth:`rc.activate` with default args.
326
328
327
329
328 Engines as Kernels
330 Engines as Kernels
329 ==================
331 ==================
330
332
331 Engines are really the same object as the Kernels used elsewhere in IPython,
333 Engines are really the same object as the Kernels used elsewhere in IPython,
332 with the minor exception that engines connect to a controller, while regular kernels
334 with the minor exception that engines connect to a controller, while regular kernels
333 bind their sockets, listening for connections from a QtConsole or other frontends.
335 bind their sockets, listening for connections from a QtConsole or other frontends.
334
336
335 Sometimes for debugging or inspection purposes, you would like a QtConsole connected
337 Sometimes for debugging or inspection purposes, you would like a QtConsole connected
336 to an engine for more direct interaction. You can do this by first instructing
338 to an engine for more direct interaction. You can do this by first instructing
337 the Engine to *also* bind its kernel, to listen for connections:
339 the Engine to *also* bind its kernel, to listen for connections:
338
340
339 .. sourcecode:: ipython
341 .. sourcecode:: ipython
340
342
341 In [50]: %px from IPython.parallel import bind_kernel; bind_kernel()
343 In [50]: %px from IPython.parallel import bind_kernel; bind_kernel()
342
344
343 Then, if your engines are local, you can start a qtconsole right on the engine(s):
345 Then, if your engines are local, you can start a qtconsole right on the engine(s):
344
346
345 .. sourcecode:: ipython
347 .. sourcecode:: ipython
346
348
347 In [51]: %px %qtconsole
349 In [51]: %px %qtconsole
348
350
349 Careful with this one, because if your view is of 16 engines it will start 16 QtConsoles!
351 Careful with this one, because if your view is of 16 engines it will start 16 QtConsoles!
350
352
351 Or you can view just the connection info, and work out the right way to connect to the engines,
353 Or you can view just the connection info, and work out the right way to connect to the engines,
352 depending on where they live and where you are:
354 depending on where they live and where you are:
353
355
354 .. sourcecode:: ipython
356 .. sourcecode:: ipython
355
357
356 In [51]: %px %connect_info
358 In [51]: %px %connect_info
357 Parallel execution on engine(s): all
359 Parallel execution on engine(s): all
358 [stdout:0]
360 [stdout:0]
359 {
361 {
360 "stdin_port": 60387,
362 "stdin_port": 60387,
361 "ip": "127.0.0.1",
363 "ip": "127.0.0.1",
362 "hb_port": 50835,
364 "hb_port": 50835,
363 "key": "eee2dd69-7dd3-4340-bf3e-7e2e22a62542",
365 "key": "eee2dd69-7dd3-4340-bf3e-7e2e22a62542",
364 "shell_port": 55328,
366 "shell_port": 55328,
365 "iopub_port": 58264
367 "iopub_port": 58264
366 }
368 }
367
369
368 Paste the above JSON into a file, and connect with:
370 Paste the above JSON into a file, and connect with:
369 $> ipython <app> --existing <file>
371 $> ipython <app> --existing <file>
370 or, if you are local, you can connect with just:
372 or, if you are local, you can connect with just:
371 $> ipython <app> --existing kernel-60125.json
373 $> ipython <app> --existing kernel-60125.json
372 or even just:
374 or even just:
373 $> ipython <app> --existing
375 $> ipython <app> --existing
374 if this is the most recent IPython session you have started.
376 if this is the most recent IPython session you have started.
375 [stdout:1]
377 [stdout:1]
376 {
378 {
377 "stdin_port": 61869,
379 "stdin_port": 61869,
378 ...
380 ...
379
381
380 .. note::
382 .. note::
381
383
382 ``%qtconsole`` will call :func:`bind_kernel` on an engine if it hasn't been done already,
384 ``%qtconsole`` will call :func:`bind_kernel` on an engine if it hasn't been done already,
383 so you can often skip that first step.
385 so you can often skip that first step.
384
386
385
387
@@ -1,652 +1,656 b''
1 .. _parallel_details:
1 .. _parallel_details:
2
2
3 ==========================================
3 ==========================================
4 Details of Parallel Computing with IPython
4 Details of Parallel Computing with IPython
5 ==========================================
5 ==========================================
6
6
7 .. note::
7 .. note::
8
8
9 There are still many sections to fill out in this doc
9 There are still many sections to fill out in this doc
10
10
11
11
12 Caveats
12 Caveats
13 =======
13 =======
14
14
15 First, some caveats about the detailed workings of parallel computing with 0MQ and IPython.
15 First, some caveats about the detailed workings of parallel computing with 0MQ and IPython.
16
16
17 Non-copying sends and numpy arrays
17 Non-copying sends and numpy arrays
18 ----------------------------------
18 ----------------------------------
19
19
20 When numpy arrays are passed as arguments to apply or via data-movement methods, they are not
20 When numpy arrays are passed as arguments to apply or via data-movement methods, they are not
21 copied. This means that you must be careful if you are sending an array that you intend to work
21 copied. This means that you must be careful if you are sending an array that you intend to work
22 on. PyZMQ does allow you to track when a message has been sent so you can know when it is safe
22 on. PyZMQ does allow you to track when a message has been sent so you can know when it is safe
23 to edit the buffer, but IPython only allows for this.
23 to edit the buffer, but IPython only allows for this.
24
24
25 It is also important to note that the non-copying receive of a message is *read-only*. That
25 It is also important to note that the non-copying receive of a message is *read-only*. That
26 means that if you intend to work in-place on an array that you have sent or received, you must
26 means that if you intend to work in-place on an array that you have sent or received, you must
27 copy it. This is true for both numpy arrays sent to engines and numpy arrays retrieved as
27 copy it. This is true for both numpy arrays sent to engines and numpy arrays retrieved as
28 results.
28 results.
29
29
30 The following will fail:
30 The following will fail:
31
31
32 .. sourcecode:: ipython
32 .. sourcecode:: ipython
33
33
34 In [3]: A = numpy.zeros(2)
34 In [3]: A = numpy.zeros(2)
35
35
36 In [4]: def setter(a):
36 In [4]: def setter(a):
37 ...: a[0]=1
37 ...: a[0]=1
38 ...: return a
38 ...: return a
39
39
40 In [5]: rc[0].apply_sync(setter, A)
40 In [5]: rc[0].apply_sync(setter, A)
41 ---------------------------------------------------------------------------
41 ---------------------------------------------------------------------------
42 RuntimeError Traceback (most recent call last)<string> in <module>()
42 RuntimeError Traceback (most recent call last)<string> in <module>()
43 <ipython-input-12-c3e7afeb3075> in setter(a)
43 <ipython-input-12-c3e7afeb3075> in setter(a)
44 RuntimeError: array is not writeable
44 RuntimeError: array is not writeable
45
45
46 If you do need to edit the array in-place, just remember to copy the array if it's read-only.
46 If you do need to edit the array in-place, just remember to copy the array if it's read-only.
47 The :attr:`ndarray.flags.writeable` flag will tell you if you can write to an array.
47 The :attr:`ndarray.flags.writeable` flag will tell you if you can write to an array.
48
48
49 .. sourcecode:: ipython
49 .. sourcecode:: ipython
50
50
51 In [3]: A = numpy.zeros(2)
51 In [3]: A = numpy.zeros(2)
52
52
53 In [4]: def setter(a):
53 In [4]: def setter(a):
54 ...: """only copy read-only arrays"""
54 ...: """only copy read-only arrays"""
55 ...: if not a.flags.writeable:
55 ...: if not a.flags.writeable:
56 ...: a=a.copy()
56 ...: a=a.copy()
57 ...: a[0]=1
57 ...: a[0]=1
58 ...: return a
58 ...: return a
59
59
60 In [5]: rc[0].apply_sync(setter, A)
60 In [5]: rc[0].apply_sync(setter, A)
61 Out[5]: array([ 1., 0.])
61 Out[5]: array([ 1., 0.])
62
62
63 # note that results will also be read-only:
63 # note that results will also be read-only:
64 In [6]: _.flags.writeable
64 In [6]: _.flags.writeable
65 Out[6]: False
65 Out[6]: False
66
66
67 If you want to safely edit an array in-place after *sending* it, you must use the `track=True`
67 If you want to safely edit an array in-place after *sending* it, you must use the `track=True`
68 flag. IPython always performs non-copying sends of arrays, which return immediately. You must
68 flag. IPython always performs non-copying sends of arrays, which return immediately. You must
69 instruct IPython track those messages *at send time* in order to know for sure that the send has
69 instruct IPython track those messages *at send time* in order to know for sure that the send has
70 completed. AsyncResults have a :attr:`sent` property, and :meth:`wait_on_send` method for
70 completed. AsyncResults have a :attr:`sent` property, and :meth:`wait_on_send` method for
71 checking and waiting for 0MQ to finish with a buffer.
71 checking and waiting for 0MQ to finish with a buffer.
72
72
73 .. sourcecode:: ipython
73 .. sourcecode:: ipython
74
74
75 In [5]: A = numpy.random.random((1024,1024))
75 In [5]: A = numpy.random.random((1024,1024))
76
76
77 In [6]: view.track=True
77 In [6]: view.track=True
78
78
79 In [7]: ar = view.apply_async(lambda x: 2*x, A)
79 In [7]: ar = view.apply_async(lambda x: 2*x, A)
80
80
81 In [8]: ar.sent
81 In [8]: ar.sent
82 Out[8]: False
82 Out[8]: False
83
83
84 In [9]: ar.wait_on_send() # blocks until sent is True
84 In [9]: ar.wait_on_send() # blocks until sent is True
85
85
86
86
87 What is sendable?
87 What is sendable?
88 -----------------
88 -----------------
89
89
90 If IPython doesn't know what to do with an object, it will pickle it. There is a short list of
90 If IPython doesn't know what to do with an object, it will pickle it. There is a short list of
91 objects that are not pickled: ``buffers``, ``str/bytes`` objects, and ``numpy``
91 objects that are not pickled: ``buffers``, ``str/bytes`` objects, and ``numpy``
92 arrays. These are handled specially by IPython in order to prevent the copying of data. Sending
92 arrays. These are handled specially by IPython in order to prevent the copying of data. Sending
93 bytes or numpy arrays will result in exactly zero in-memory copies of your data (unless the data
93 bytes or numpy arrays will result in exactly zero in-memory copies of your data (unless the data
94 is very small).
94 is very small).
95
95
96 If you have an object that provides a Python buffer interface, then you can always send that
96 If you have an object that provides a Python buffer interface, then you can always send that
97 buffer without copying - and reconstruct the object on the other side in your own code. It is
97 buffer without copying - and reconstruct the object on the other side in your own code. It is
98 possible that the object reconstruction will become extensible, so you can add your own
98 possible that the object reconstruction will become extensible, so you can add your own
99 non-copying types, but this does not yet exist.
99 non-copying types, but this does not yet exist.
100
100
101 Closures
101 Closures
102 ********
102 ********
103
103
104 Just about anything in Python is pickleable. The one notable exception is objects (generally
104 Just about anything in Python is pickleable. The one notable exception is objects (generally
105 functions) with *closures*. Closures can be a complicated topic, but the basic principal is that
105 functions) with *closures*. Closures can be a complicated topic, but the basic principal is that
106 functions that refer to variables in their parent scope have closures.
106 functions that refer to variables in their parent scope have closures.
107
107
108 An example of a function that uses a closure:
108 An example of a function that uses a closure:
109
109
110 .. sourcecode:: python
110 .. sourcecode:: python
111
111
112 def f(a):
112 def f(a):
113 def inner():
113 def inner():
114 # inner will have a closure
114 # inner will have a closure
115 return a
115 return a
116 return inner
116 return inner
117
117
118 f1 = f(1)
118 f1 = f(1)
119 f2 = f(2)
119 f2 = f(2)
120 f1() # returns 1
120 f1() # returns 1
121 f2() # returns 2
121 f2() # returns 2
122
122
123 ``f1`` and ``f2`` will have closures referring to the scope in which `inner` was defined,
123 ``f1`` and ``f2`` will have closures referring to the scope in which `inner` was defined,
124 because they use the variable 'a'. As a result, you would not be able to send ``f1`` or ``f2``
124 because they use the variable 'a'. As a result, you would not be able to send ``f1`` or ``f2``
125 with IPython. Note that you *would* be able to send `f`. This is only true for interactively
125 with IPython. Note that you *would* be able to send `f`. This is only true for interactively
126 defined functions (as are often used in decorators), and only when there are variables used
126 defined functions (as are often used in decorators), and only when there are variables used
127 inside the inner function, that are defined in the outer function. If the names are *not* in the
127 inside the inner function, that are defined in the outer function. If the names are *not* in the
128 outer function, then there will not be a closure, and the generated function will look in
128 outer function, then there will not be a closure, and the generated function will look in
129 ``globals()`` for the name:
129 ``globals()`` for the name:
130
130
131 .. sourcecode:: python
131 .. sourcecode:: python
132
132
133 def g(b):
133 def g(b):
134 # note that `b` is not referenced in inner's scope
134 # note that `b` is not referenced in inner's scope
135 def inner():
135 def inner():
136 # this inner will *not* have a closure
136 # this inner will *not* have a closure
137 return a
137 return a
138 return inner
138 return inner
139 g1 = g(1)
139 g1 = g(1)
140 g2 = g(2)
140 g2 = g(2)
141 g1() # raises NameError on 'a'
141 g1() # raises NameError on 'a'
142 a=5
142 a=5
143 g2() # returns 5
143 g2() # returns 5
144
144
145 `g1` and `g2` *will* be sendable with IPython, and will treat the engine's namespace as
145 `g1` and `g2` *will* be sendable with IPython, and will treat the engine's namespace as
146 globals(). The :meth:`pull` method is implemented based on this principle. If we did not
146 globals(). The :meth:`pull` method is implemented based on this principle. If we did not
147 provide pull, you could implement it yourself with `apply`, by simply returning objects out
147 provide pull, you could implement it yourself with `apply`, by simply returning objects out
148 of the global namespace:
148 of the global namespace:
149
149
150 .. sourcecode:: ipython
150 .. sourcecode:: ipython
151
151
152 In [10]: view.apply(lambda : a)
152 In [10]: view.apply(lambda : a)
153
153
154 # is equivalent to
154 # is equivalent to
155 In [11]: view.pull('a')
155 In [11]: view.pull('a')
156
156
157 Running Code
157 Running Code
158 ============
158 ============
159
159
160 There are two principal units of execution in Python: strings of Python code (e.g. 'a=5'),
160 There are two principal units of execution in Python: strings of Python code (e.g. 'a=5'),
161 and Python functions. IPython is designed around the use of functions via the core
161 and Python functions. IPython is designed around the use of functions via the core
162 Client method, called `apply`.
162 Client method, called `apply`.
163
163
164 Apply
164 Apply
165 -----
165 -----
166
166
167 The principal method of remote execution is :meth:`apply`, of
167 The principal method of remote execution is :meth:`apply`, of
168 :class:`~IPython.parallel.client.view.View` objects. The Client provides the full execution and
168 :class:`~IPython.parallel.client.view.View` objects. The Client provides the full execution and
169 communication API for engines via its low-level :meth:`send_apply_message` method, which is used
169 communication API for engines via its low-level :meth:`send_apply_message` method, which is used
170 by all higher level methods of its Views.
170 by all higher level methods of its Views.
171
171
172 f : function
172 f : function
173 The fuction to be called remotely
173 The fuction to be called remotely
174 args : tuple/list
174 args : tuple/list
175 The positional arguments passed to `f`
175 The positional arguments passed to `f`
176 kwargs : dict
176 kwargs : dict
177 The keyword arguments passed to `f`
177 The keyword arguments passed to `f`
178
178
179 flags for all views:
179 flags for all views:
180
180
181 block : bool (default: view.block)
181 block : bool (default: view.block)
182 Whether to wait for the result, or return immediately.
182 Whether to wait for the result, or return immediately.
183
183 False:
184 False:
184 returns AsyncResult
185 returns AsyncResult
185 True:
186 True:
186 returns actual result(s) of f(*args, **kwargs)
187 returns actual result(s) of ``f(*args, **kwargs)``
188
187 if multiple targets:
189 if multiple targets:
188 list of results, matching `targets`
190 list of results, matching `targets`
191
189 track : bool [default view.track]
192 track : bool [default view.track]
190 whether to track non-copying sends.
193 whether to track non-copying sends.
191
194
192 targets : int,list of ints, 'all', None [default view.targets]
195 targets : int,list of ints, 'all', None [default view.targets]
193 Specify the destination of the job.
196 Specify the destination of the job.
197
194 if 'all' or None:
198 if 'all' or None:
195 Run on all active engines
199 Run on all active engines
196 if list:
200 if list:
197 Run on each specified engine
201 Run on each specified engine
198 if int:
202 if int:
199 Run on single engine
203 Run on single engine
200
204
201 Note that LoadBalancedView uses targets to restrict possible destinations. LoadBalanced calls
205 Note that :class:`LoadBalancedView` uses targets to restrict possible destinations.
202 will always execute in just one location.
206 LoadBalanced calls will always execute in just one location.
203
207
204 flags only in LoadBalancedViews:
208 flags only in LoadBalancedViews:
205
209
206 after : Dependency or collection of msg_ids
210 after : Dependency or collection of msg_ids
207 Only for load-balanced execution (targets=None)
211 Only for load-balanced execution (targets=None)
208 Specify a list of msg_ids as a time-based dependency.
212 Specify a list of msg_ids as a time-based dependency.
209 This job will only be run *after* the dependencies
213 This job will only be run *after* the dependencies
210 have been met.
214 have been met.
211
215
212 follow : Dependency or collection of msg_ids
216 follow : Dependency or collection of msg_ids
213 Only for load-balanced execution (targets=None)
217 Only for load-balanced execution (targets=None)
214 Specify a list of msg_ids as a location-based dependency.
218 Specify a list of msg_ids as a location-based dependency.
215 This job will only be run on an engine where this dependency
219 This job will only be run on an engine where this dependency
216 is met.
220 is met.
217
221
218 timeout : float/int or None
222 timeout : float/int or None
219 Only for load-balanced execution (targets=None)
223 Only for load-balanced execution (targets=None)
220 Specify an amount of time (in seconds) for the scheduler to
224 Specify an amount of time (in seconds) for the scheduler to
221 wait for dependencies to be met before failing with a
225 wait for dependencies to be met before failing with a
222 DependencyTimeout.
226 DependencyTimeout.
223
227
224 execute and run
228 execute and run
225 ---------------
229 ---------------
226
230
227 For executing strings of Python code, :class:`DirectView` 's also provide an :meth:`execute` and
231 For executing strings of Python code, :class:`DirectView` 's also provide an :meth:`execute` and
228 a :meth:`run` method, which rather than take functions and arguments, take simple strings.
232 a :meth:`run` method, which rather than take functions and arguments, take simple strings.
229 `execute` simply takes a string of Python code to execute, and sends it to the Engine(s). `run`
233 `execute` simply takes a string of Python code to execute, and sends it to the Engine(s). `run`
230 is the same as `execute`, but for a *file*, rather than a string. It is simply a wrapper that
234 is the same as `execute`, but for a *file*, rather than a string. It is simply a wrapper that
231 does something very similar to ``execute(open(f).read())``.
235 does something very similar to ``execute(open(f).read())``.
232
236
233 .. note::
237 .. note::
234
238
235 TODO: Examples for execute and run
239 TODO: Examples for execute and run
236
240
237 Views
241 Views
238 =====
242 =====
239
243
240 The principal extension of the :class:`~parallel.Client` is the :class:`~parallel.View`
244 The principal extension of the :class:`~parallel.Client` is the :class:`~parallel.View`
241 class. The client is typically a singleton for connecting to a cluster, and presents a
245 class. The client is typically a singleton for connecting to a cluster, and presents a
242 low-level interface to the Hub and Engines. Most real usage will involve creating one or more
246 low-level interface to the Hub and Engines. Most real usage will involve creating one or more
243 :class:`~parallel.View` objects for working with engines in various ways.
247 :class:`~parallel.View` objects for working with engines in various ways.
244
248
245
249
246 DirectView
250 DirectView
247 ----------
251 ----------
248
252
249 The :class:`.DirectView` is the class for the IPython :ref:`Multiplexing Interface
253 The :class:`.DirectView` is the class for the IPython :ref:`Multiplexing Interface
250 <parallel_multiengine>`.
254 <parallel_multiengine>`.
251
255
252 Creating a DirectView
256 Creating a DirectView
253 *********************
257 *********************
254
258
255 DirectViews can be created in two ways, by index access to a client, or by a client's
259 DirectViews can be created in two ways, by index access to a client, or by a client's
256 :meth:`view` method. Index access to a Client works in a few ways. First, you can create
260 :meth:`view` method. Index access to a Client works in a few ways. First, you can create
257 DirectViews to single engines simply by accessing the client by engine id:
261 DirectViews to single engines simply by accessing the client by engine id:
258
262
259 .. sourcecode:: ipython
263 .. sourcecode:: ipython
260
264
261 In [2]: rc[0]
265 In [2]: rc[0]
262 Out[2]: <DirectView 0>
266 Out[2]: <DirectView 0>
263
267
264 You can also create a DirectView with a list of engines:
268 You can also create a DirectView with a list of engines:
265
269
266 .. sourcecode:: ipython
270 .. sourcecode:: ipython
267
271
268 In [2]: rc[0,1,2]
272 In [2]: rc[0,1,2]
269 Out[2]: <DirectView [0,1,2]>
273 Out[2]: <DirectView [0,1,2]>
270
274
271 Other methods for accessing elements, such as slicing and negative indexing, work by passing
275 Other methods for accessing elements, such as slicing and negative indexing, work by passing
272 the index directly to the client's :attr:`ids` list, so:
276 the index directly to the client's :attr:`ids` list, so:
273
277
274 .. sourcecode:: ipython
278 .. sourcecode:: ipython
275
279
276 # negative index
280 # negative index
277 In [2]: rc[-1]
281 In [2]: rc[-1]
278 Out[2]: <DirectView 3>
282 Out[2]: <DirectView 3>
279
283
280 # or slicing:
284 # or slicing:
281 In [3]: rc[::2]
285 In [3]: rc[::2]
282 Out[3]: <DirectView [0,2]>
286 Out[3]: <DirectView [0,2]>
283
287
284 are always the same as:
288 are always the same as:
285
289
286 .. sourcecode:: ipython
290 .. sourcecode:: ipython
287
291
288 In [2]: rc[rc.ids[-1]]
292 In [2]: rc[rc.ids[-1]]
289 Out[2]: <DirectView 3>
293 Out[2]: <DirectView 3>
290
294
291 In [3]: rc[rc.ids[::2]]
295 In [3]: rc[rc.ids[::2]]
292 Out[3]: <DirectView [0,2]>
296 Out[3]: <DirectView [0,2]>
293
297
294 Also note that the slice is evaluated at the time of construction of the DirectView, so the
298 Also note that the slice is evaluated at the time of construction of the DirectView, so the
295 targets will not change over time if engines are added/removed from the cluster.
299 targets will not change over time if engines are added/removed from the cluster.
296
300
297 Execution via DirectView
301 Execution via DirectView
298 ************************
302 ************************
299
303
300 The DirectView is the simplest way to work with one or more engines directly (hence the name).
304 The DirectView is the simplest way to work with one or more engines directly (hence the name).
301
305
302 For instance, to get the process ID of all your engines:
306 For instance, to get the process ID of all your engines:
303
307
304 .. sourcecode:: ipython
308 .. sourcecode:: ipython
305
309
306 In [5]: import os
310 In [5]: import os
307
311
308 In [6]: dview.apply_sync(os.getpid)
312 In [6]: dview.apply_sync(os.getpid)
309 Out[6]: [1354, 1356, 1358, 1360]
313 Out[6]: [1354, 1356, 1358, 1360]
310
314
311 Or to see the hostname of the machine they are on:
315 Or to see the hostname of the machine they are on:
312
316
313 .. sourcecode:: ipython
317 .. sourcecode:: ipython
314
318
315 In [5]: import socket
319 In [5]: import socket
316
320
317 In [6]: dview.apply_sync(socket.gethostname)
321 In [6]: dview.apply_sync(socket.gethostname)
318 Out[6]: ['tesla', 'tesla', 'edison', 'edison', 'edison']
322 Out[6]: ['tesla', 'tesla', 'edison', 'edison', 'edison']
319
323
320 .. note::
324 .. note::
321
325
322 TODO: expand on direct execution
326 TODO: expand on direct execution
323
327
324 Data movement via DirectView
328 Data movement via DirectView
325 ****************************
329 ****************************
326
330
327 Since a Python namespace is just a :class:`dict`, :class:`DirectView` objects provide
331 Since a Python namespace is just a :class:`dict`, :class:`DirectView` objects provide
328 dictionary-style access by key and methods such as :meth:`get` and
332 dictionary-style access by key and methods such as :meth:`get` and
329 :meth:`update` for convenience. This make the remote namespaces of the engines
333 :meth:`update` for convenience. This make the remote namespaces of the engines
330 appear as a local dictionary. Underneath, these methods call :meth:`apply`:
334 appear as a local dictionary. Underneath, these methods call :meth:`apply`:
331
335
332 .. sourcecode:: ipython
336 .. sourcecode:: ipython
333
337
334 In [51]: dview['a']=['foo','bar']
338 In [51]: dview['a']=['foo','bar']
335
339
336 In [52]: dview['a']
340 In [52]: dview['a']
337 Out[52]: [ ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'] ]
341 Out[52]: [ ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'] ]
338
342
339 Scatter and gather
343 Scatter and gather
340 ------------------
344 ------------------
341
345
342 Sometimes it is useful to partition a sequence and push the partitions to
346 Sometimes it is useful to partition a sequence and push the partitions to
343 different engines. In MPI language, this is know as scatter/gather and we
347 different engines. In MPI language, this is know as scatter/gather and we
344 follow that terminology. However, it is important to remember that in
348 follow that terminology. However, it is important to remember that in
345 IPython's :class:`Client` class, :meth:`scatter` is from the
349 IPython's :class:`Client` class, :meth:`scatter` is from the
346 interactive IPython session to the engines and :meth:`gather` is from the
350 interactive IPython session to the engines and :meth:`gather` is from the
347 engines back to the interactive IPython session. For scatter/gather operations
351 engines back to the interactive IPython session. For scatter/gather operations
348 between engines, MPI should be used:
352 between engines, MPI should be used:
349
353
350 .. sourcecode:: ipython
354 .. sourcecode:: ipython
351
355
352 In [58]: dview.scatter('a',range(16))
356 In [58]: dview.scatter('a',range(16))
353 Out[58]: [None,None,None,None]
357 Out[58]: [None,None,None,None]
354
358
355 In [59]: dview['a']
359 In [59]: dview['a']
356 Out[59]: [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15] ]
360 Out[59]: [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15] ]
357
361
358 In [60]: dview.gather('a')
362 In [60]: dview.gather('a')
359 Out[60]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
363 Out[60]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
360
364
361 Push and pull
365 Push and pull
362 -------------
366 -------------
363
367
364 :meth:`~IPython.parallel.client.view.DirectView.push`
368 :meth:`~IPython.parallel.client.view.DirectView.push`
365
369
366 :meth:`~IPython.parallel.client.view.DirectView.pull`
370 :meth:`~IPython.parallel.client.view.DirectView.pull`
367
371
368 .. note::
372 .. note::
369
373
370 TODO: write this section
374 TODO: write this section
371
375
372
376
373 LoadBalancedView
377 LoadBalancedView
374 ----------------
378 ----------------
375
379
376 The :class:`~.LoadBalancedView` is the class for load-balanced execution via the task scheduler.
380 The :class:`~.LoadBalancedView` is the class for load-balanced execution via the task scheduler.
377 These views always run tasks on exactly one engine, but let the scheduler determine where that
381 These views always run tasks on exactly one engine, but let the scheduler determine where that
378 should be, allowing load-balancing of tasks. The LoadBalancedView does allow you to specify
382 should be, allowing load-balancing of tasks. The LoadBalancedView does allow you to specify
379 restrictions on where and when tasks can execute, for more complicated load-balanced workflows.
383 restrictions on where and when tasks can execute, for more complicated load-balanced workflows.
380
384
381 Data Movement
385 Data Movement
382 =============
386 =============
383
387
384 Since the :class:`~.LoadBalancedView` does not know where execution will take place, explicit
388 Since the :class:`~.LoadBalancedView` does not know where execution will take place, explicit
385 data movement methods like push/pull and scatter/gather do not make sense, and are not provided.
389 data movement methods like push/pull and scatter/gather do not make sense, and are not provided.
386
390
387 Results
391 Results
388 =======
392 =======
389
393
390 AsyncResults
394 AsyncResults
391 ------------
395 ------------
392
396
393 Our primary representation of the results of remote execution is the :class:`~.AsyncResult`
397 Our primary representation of the results of remote execution is the :class:`~.AsyncResult`
394 object, based on the object of the same name in the built-in :mod:`multiprocessing.pool`
398 object, based on the object of the same name in the built-in :mod:`multiprocessing.pool`
395 module. Our version provides a superset of that interface.
399 module. Our version provides a superset of that interface.
396
400
397 The basic principle of the AsyncResult is the encapsulation of one or more results not yet completed. Execution methods (including data movement, such as push/pull) will all return
401 The basic principle of the AsyncResult is the encapsulation of one or more results not yet completed. Execution methods (including data movement, such as push/pull) will all return
398 AsyncResults when `block=False`.
402 AsyncResults when `block=False`.
399
403
400 The mp.pool.AsyncResult interface
404 The mp.pool.AsyncResult interface
401 ---------------------------------
405 ---------------------------------
402
406
403 The basic interface of the AsyncResult is exactly that of the AsyncResult in :mod:`multiprocessing.pool`, and consists of four methods:
407 The basic interface of the AsyncResult is exactly that of the AsyncResult in :mod:`multiprocessing.pool`, and consists of four methods:
404
408
405 .. AsyncResult spec directly from docs.python.org
409 .. AsyncResult spec directly from docs.python.org
406
410
407 .. class:: AsyncResult
411 .. class:: AsyncResult
408
412
409 The stdlib AsyncResult spec
413 The stdlib AsyncResult spec
410
414
411 .. method:: wait([timeout])
415 .. method:: wait([timeout])
412
416
413 Wait until the result is available or until *timeout* seconds pass. This
417 Wait until the result is available or until *timeout* seconds pass. This
414 method always returns ``None``.
418 method always returns ``None``.
415
419
416 .. method:: ready()
420 .. method:: ready()
417
421
418 Return whether the call has completed.
422 Return whether the call has completed.
419
423
420 .. method:: successful()
424 .. method:: successful()
421
425
422 Return whether the call completed without raising an exception. Will
426 Return whether the call completed without raising an exception. Will
423 raise :exc:`AssertionError` if the result is not ready.
427 raise :exc:`AssertionError` if the result is not ready.
424
428
425 .. method:: get([timeout])
429 .. method:: get([timeout])
426
430
427 Return the result when it arrives. If *timeout* is not ``None`` and the
431 Return the result when it arrives. If *timeout* is not ``None`` and the
428 result does not arrive within *timeout* seconds then
432 result does not arrive within *timeout* seconds then
429 :exc:`TimeoutError` is raised. If the remote call raised
433 :exc:`TimeoutError` is raised. If the remote call raised
430 an exception then that exception will be reraised as a :exc:`RemoteError`
434 an exception then that exception will be reraised as a :exc:`RemoteError`
431 by :meth:`get`.
435 by :meth:`get`.
432
436
433
437
434 While an AsyncResult is not done, you can check on it with its :meth:`ready` method, which will
438 While an AsyncResult is not done, you can check on it with its :meth:`ready` method, which will
435 return whether the AR is done. You can also wait on an AsyncResult with its :meth:`wait` method.
439 return whether the AR is done. You can also wait on an AsyncResult with its :meth:`wait` method.
436 This method blocks until the result arrives. If you don't want to wait forever, you can pass a
440 This method blocks until the result arrives. If you don't want to wait forever, you can pass a
437 timeout (in seconds) as an argument to :meth:`wait`. :meth:`wait` will *always return None*, and
441 timeout (in seconds) as an argument to :meth:`wait`. :meth:`wait` will *always return None*, and
438 should never raise an error.
442 should never raise an error.
439
443
440 :meth:`ready` and :meth:`wait` are insensitive to the success or failure of the call. After a
444 :meth:`ready` and :meth:`wait` are insensitive to the success or failure of the call. After a
441 result is done, :meth:`successful` will tell you whether the call completed without raising an
445 result is done, :meth:`successful` will tell you whether the call completed without raising an
442 exception.
446 exception.
443
447
444 If you actually want the result of the call, you can use :meth:`get`. Initially, :meth:`get`
448 If you actually want the result of the call, you can use :meth:`get`. Initially, :meth:`get`
445 behaves just like :meth:`wait`, in that it will block until the result is ready, or until a
449 behaves just like :meth:`wait`, in that it will block until the result is ready, or until a
446 timeout is met. However, unlike :meth:`wait`, :meth:`get` will raise a :exc:`TimeoutError` if
450 timeout is met. However, unlike :meth:`wait`, :meth:`get` will raise a :exc:`TimeoutError` if
447 the timeout is reached and the result is still not ready. If the result arrives before the
451 the timeout is reached and the result is still not ready. If the result arrives before the
448 timeout is reached, then :meth:`get` will return the result itself if no exception was raised,
452 timeout is reached, then :meth:`get` will return the result itself if no exception was raised,
449 and will raise an exception if there was.
453 and will raise an exception if there was.
450
454
451 Here is where we start to expand on the multiprocessing interface. Rather than raising the
455 Here is where we start to expand on the multiprocessing interface. Rather than raising the
452 original exception, a RemoteError will be raised, encapsulating the remote exception with some
456 original exception, a RemoteError will be raised, encapsulating the remote exception with some
453 metadata. If the AsyncResult represents multiple calls (e.g. any time `targets` is plural), then
457 metadata. If the AsyncResult represents multiple calls (e.g. any time `targets` is plural), then
454 a CompositeError, a subclass of RemoteError, will be raised.
458 a CompositeError, a subclass of RemoteError, will be raised.
455
459
456 .. seealso::
460 .. seealso::
457
461
458 For more information on remote exceptions, see :ref:`the section in the Direct Interface
462 For more information on remote exceptions, see :ref:`the section in the Direct Interface
459 <parallel_exceptions>`.
463 <parallel_exceptions>`.
460
464
461 Extended interface
465 Extended interface
462 ******************
466 ******************
463
467
464
468
465 Other extensions of the AsyncResult interface include convenience wrappers for :meth:`get`.
469 Other extensions of the AsyncResult interface include convenience wrappers for :meth:`get`.
466 AsyncResults have a property, :attr:`result`, with the short alias :attr:`r`, which simply call
470 AsyncResults have a property, :attr:`result`, with the short alias :attr:`r`, which simply call
467 :meth:`get`. Since our object is designed for representing *parallel* results, it is expected
471 :meth:`get`. Since our object is designed for representing *parallel* results, it is expected
468 that many calls (any of those submitted via DirectView) will map results to engine IDs. We
472 that many calls (any of those submitted via DirectView) will map results to engine IDs. We
469 provide a :meth:`get_dict`, which is also a wrapper on :meth:`get`, which returns a dictionary
473 provide a :meth:`get_dict`, which is also a wrapper on :meth:`get`, which returns a dictionary
470 of the individual results, keyed by engine ID.
474 of the individual results, keyed by engine ID.
471
475
472 You can also prevent a submitted job from actually executing, via the AsyncResult's
476 You can also prevent a submitted job from actually executing, via the AsyncResult's
473 :meth:`abort` method. This will instruct engines to not execute the job when it arrives.
477 :meth:`abort` method. This will instruct engines to not execute the job when it arrives.
474
478
475 The larger extension of the AsyncResult API is the :attr:`metadata` attribute. The metadata
479 The larger extension of the AsyncResult API is the :attr:`metadata` attribute. The metadata
476 is a dictionary (with attribute access) that contains, logically enough, metadata about the
480 is a dictionary (with attribute access) that contains, logically enough, metadata about the
477 execution.
481 execution.
478
482
479 Metadata keys:
483 Metadata keys:
480
484
481 timestamps
485 timestamps
482
486
483 submitted
487 submitted
484 When the task left the Client
488 When the task left the Client
485 started
489 started
486 When the task started execution on the engine
490 When the task started execution on the engine
487 completed
491 completed
488 When execution finished on the engine
492 When execution finished on the engine
489 received
493 received
490 When the result arrived on the Client
494 When the result arrived on the Client
491
495
492 note that it is not known when the result arrived in 0MQ on the client, only when it
496 note that it is not known when the result arrived in 0MQ on the client, only when it
493 arrived in Python via :meth:`Client.spin`, so in interactive use, this may not be
497 arrived in Python via :meth:`Client.spin`, so in interactive use, this may not be
494 strictly informative.
498 strictly informative.
495
499
496 Information about the engine
500 Information about the engine
497
501
498 engine_id
502 engine_id
499 The integer id
503 The integer id
500 engine_uuid
504 engine_uuid
501 The UUID of the engine
505 The UUID of the engine
502
506
503 output of the call
507 output of the call
504
508
505 pyerr
509 pyerr
506 Python exception, if there was one
510 Python exception, if there was one
507 pyout
511 pyout
508 Python output
512 Python output
509 stderr
513 stderr
510 stderr stream
514 stderr stream
511 stdout
515 stdout
512 stdout (e.g. print) stream
516 stdout (e.g. print) stream
513
517
514 And some extended information
518 And some extended information
515
519
516 status
520 status
517 either 'ok' or 'error'
521 either 'ok' or 'error'
518 msg_id
522 msg_id
519 The UUID of the message
523 The UUID of the message
520 after
524 after
521 For tasks: the time-based msg_id dependencies
525 For tasks: the time-based msg_id dependencies
522 follow
526 follow
523 For tasks: the location-based msg_id dependencies
527 For tasks: the location-based msg_id dependencies
524
528
525 While in most cases, the Clients that submitted a request will be the ones using the results,
529 While in most cases, the Clients that submitted a request will be the ones using the results,
526 other Clients can also request results directly from the Hub. This is done via the Client's
530 other Clients can also request results directly from the Hub. This is done via the Client's
527 :meth:`get_result` method. This method will *always* return an AsyncResult object. If the call
531 :meth:`get_result` method. This method will *always* return an AsyncResult object. If the call
528 was not submitted by the client, then it will be a subclass, called :class:`AsyncHubResult`.
532 was not submitted by the client, then it will be a subclass, called :class:`AsyncHubResult`.
529 These behave in the same way as an AsyncResult, but if the result is not ready, waiting on an
533 These behave in the same way as an AsyncResult, but if the result is not ready, waiting on an
530 AsyncHubResult polls the Hub, which is much more expensive than the passive polling used
534 AsyncHubResult polls the Hub, which is much more expensive than the passive polling used
531 in regular AsyncResults.
535 in regular AsyncResults.
532
536
533
537
534 The Client keeps track of all results
538 The Client keeps track of all results
535 history, results, metadata
539 history, results, metadata
536
540
537 Querying the Hub
541 Querying the Hub
538 ================
542 ================
539
543
540 The Hub sees all traffic that may pass through the schedulers between engines and clients.
544 The Hub sees all traffic that may pass through the schedulers between engines and clients.
541 It does this so that it can track state, allowing multiple clients to retrieve results of
545 It does this so that it can track state, allowing multiple clients to retrieve results of
542 computations submitted by their peers, as well as persisting the state to a database.
546 computations submitted by their peers, as well as persisting the state to a database.
543
547
544 queue_status
548 queue_status
545
549
546 You can check the status of the queues of the engines with this command.
550 You can check the status of the queues of the engines with this command.
547
551
548 result_status
552 result_status
549
553
550 check on results
554 check on results
551
555
552 purge_results
556 purge_results
553
557
554 forget results (conserve resources)
558 forget results (conserve resources)
555
559
556 Controlling the Engines
560 Controlling the Engines
557 =======================
561 =======================
558
562
559 There are a few actions you can do with Engines that do not involve execution. These
563 There are a few actions you can do with Engines that do not involve execution. These
560 messages are sent via the Control socket, and bypass any long queues of waiting execution
564 messages are sent via the Control socket, and bypass any long queues of waiting execution
561 jobs
565 jobs
562
566
563 abort
567 abort
564
568
565 Sometimes you may want to prevent a job you have submitted from actually running. The method
569 Sometimes you may want to prevent a job you have submitted from actually running. The method
566 for this is :meth:`abort`. It takes a container of msg_ids, and instructs the Engines to not
570 for this is :meth:`abort`. It takes a container of msg_ids, and instructs the Engines to not
567 run the jobs if they arrive. The jobs will then fail with an AbortedTask error.
571 run the jobs if they arrive. The jobs will then fail with an AbortedTask error.
568
572
569 clear
573 clear
570
574
571 You may want to purge the Engine(s) namespace of any data you have left in it. After
575 You may want to purge the Engine(s) namespace of any data you have left in it. After
572 running `clear`, there will be no names in the Engine's namespace
576 running `clear`, there will be no names in the Engine's namespace
573
577
574 shutdown
578 shutdown
575
579
576 You can also instruct engines (and the Controller) to terminate from a Client. This
580 You can also instruct engines (and the Controller) to terminate from a Client. This
577 can be useful when a job is finished, since you can shutdown all the processes with a
581 can be useful when a job is finished, since you can shutdown all the processes with a
578 single command.
582 single command.
579
583
580 Synchronization
584 Synchronization
581 ===============
585 ===============
582
586
583 Since the Client is a synchronous object, events do not automatically trigger in your
587 Since the Client is a synchronous object, events do not automatically trigger in your
584 interactive session - you must poll the 0MQ sockets for incoming messages. Note that
588 interactive session - you must poll the 0MQ sockets for incoming messages. Note that
585 this polling *does not* actually make any network requests. It simply performs a `select`
589 this polling *does not* actually make any network requests. It simply performs a `select`
586 operation, to check if messages are already in local memory, waiting to be handled.
590 operation, to check if messages are already in local memory, waiting to be handled.
587
591
588 The method that handles incoming messages is :meth:`spin`. This method flushes any waiting
592 The method that handles incoming messages is :meth:`spin`. This method flushes any waiting
589 messages on the various incoming sockets, and updates the state of the Client.
593 messages on the various incoming sockets, and updates the state of the Client.
590
594
591 If you need to wait for particular results to finish, you can use the :meth:`wait` method,
595 If you need to wait for particular results to finish, you can use the :meth:`wait` method,
592 which will call :meth:`spin` until the messages are no longer outstanding. Anything that
596 which will call :meth:`spin` until the messages are no longer outstanding. Anything that
593 represents a collection of messages, such as a list of msg_ids or one or more AsyncResult
597 represents a collection of messages, such as a list of msg_ids or one or more AsyncResult
594 objects, can be passed as argument to wait. A timeout can be specified, which will prevent
598 objects, can be passed as argument to wait. A timeout can be specified, which will prevent
595 the call from blocking for more than a specified time, but the default behavior is to wait
599 the call from blocking for more than a specified time, but the default behavior is to wait
596 forever.
600 forever.
597
601
598 The client also has an ``outstanding`` attribute - a ``set`` of msg_ids that are awaiting
602 The client also has an ``outstanding`` attribute - a ``set`` of msg_ids that are awaiting
599 replies. This is the default if wait is called with no arguments - i.e. wait on *all*
603 replies. This is the default if wait is called with no arguments - i.e. wait on *all*
600 outstanding messages.
604 outstanding messages.
601
605
602
606
603 .. note::
607 .. note::
604
608
605 TODO wait example
609 TODO wait example
606
610
607 Map
611 Map
608 ===
612 ===
609
613
610 Many parallel computing problems can be expressed as a ``map``, or running a single program with
614 Many parallel computing problems can be expressed as a ``map``, or running a single program with
611 a variety of different inputs. Python has a built-in :py:func:`map`, which does exactly this,
615 a variety of different inputs. Python has a built-in :py:func:`map`, which does exactly this,
612 and many parallel execution tools in Python, such as the built-in
616 and many parallel execution tools in Python, such as the built-in
613 :py:class:`multiprocessing.Pool` object provide implementations of `map`. All View objects
617 :py:class:`multiprocessing.Pool` object provide implementations of `map`. All View objects
614 provide a :meth:`map` method as well, but the load-balanced and direct implementations differ.
618 provide a :meth:`map` method as well, but the load-balanced and direct implementations differ.
615
619
616 Views' map methods can be called on any number of sequences, but they can also take the `block`
620 Views' map methods can be called on any number of sequences, but they can also take the `block`
617 and `bound` keyword arguments, just like :meth:`~client.apply`, but *only as keywords*.
621 and `bound` keyword arguments, just like :meth:`~client.apply`, but *only as keywords*.
618
622
619 .. sourcecode:: python
623 .. sourcecode:: python
620
624
621 dview.map(*sequences, block=None)
625 dview.map(*sequences, block=None)
622
626
623
627
624 * iter, map_async, reduce
628 * iter, map_async, reduce
625
629
626 Decorators and RemoteFunctions
630 Decorators and RemoteFunctions
627 ==============================
631 ==============================
628
632
629 .. note::
633 .. note::
630
634
631 TODO: write this section
635 TODO: write this section
632
636
633 :func:`~IPython.parallel.client.remotefunction.@parallel`
637 :func:`~IPython.parallel.client.remotefunction.@parallel`
634
638
635 :func:`~IPython.parallel.client.remotefunction.@remote`
639 :func:`~IPython.parallel.client.remotefunction.@remote`
636
640
637 :class:`~IPython.parallel.client.remotefunction.RemoteFunction`
641 :class:`~IPython.parallel.client.remotefunction.RemoteFunction`
638
642
639 :class:`~IPython.parallel.client.remotefunction.ParallelFunction`
643 :class:`~IPython.parallel.client.remotefunction.ParallelFunction`
640
644
641 Dependencies
645 Dependencies
642 ============
646 ============
643
647
644 .. note::
648 .. note::
645
649
646 TODO: write this section
650 TODO: write this section
647
651
648 :func:`~IPython.parallel.controller.dependency.@depend`
652 :func:`~IPython.parallel.controller.dependency.@depend`
649
653
650 :func:`~IPython.parallel.controller.dependency.@require`
654 :func:`~IPython.parallel.controller.dependency.@require`
651
655
652 :class:`~IPython.parallel.controller.dependency.Dependency`
656 :class:`~IPython.parallel.controller.dependency.Dependency`
@@ -1,245 +1,245 b''
1 .. _parallel_transition:
1 .. _parallel_transition:
2
2
3 =====================================================
3 =====================================================
4 Transitioning from IPython.kernel to IPython.parallel
4 Transitioning from IPython.kernel to IPython.parallel
5 =====================================================
5 =====================================================
6
6
7
7
8 We have rewritten our parallel computing tools to use 0MQ_ and Tornado_. The redesign
8 We have rewritten our parallel computing tools to use 0MQ_ and Tornado_. The redesign
9 has resulted in dramatically improved performance, as well as (we think), an improved
9 has resulted in dramatically improved performance, as well as (we think), an improved
10 interface for executing code remotely. This doc is to help users of IPython.kernel
10 interface for executing code remotely. This doc is to help users of IPython.kernel
11 transition their codes to the new code.
11 transition their codes to the new code.
12
12
13 .. _0MQ: http://zeromq.org
13 .. _0MQ: http://zeromq.org
14 .. _Tornado: https://github.com/facebook/tornado
14 .. _Tornado: https://github.com/facebook/tornado
15
15
16
16
17 Processes
17 Processes
18 =========
18 =========
19
19
20 The process model for the new parallel code is very similar to that of IPython.kernel. There is
20 The process model for the new parallel code is very similar to that of IPython.kernel. There is
21 still a Controller, Engines, and Clients. However, the the Controller is now split into multiple
21 still a Controller, Engines, and Clients. However, the the Controller is now split into multiple
22 processes, and can even be split across multiple machines. There does remain a single
22 processes, and can even be split across multiple machines. There does remain a single
23 ipcontroller script for starting all of the controller processes.
23 ipcontroller script for starting all of the controller processes.
24
24
25
25
26 .. note::
26 .. note::
27
27
28 TODO: fill this out after config system is updated
28 TODO: fill this out after config system is updated
29
29
30
30
31 .. seealso::
31 .. seealso::
32
32
33 Detailed :ref:`Parallel Process <parallel_process>` doc for configuring and launching
33 Detailed :ref:`Parallel Process <parallel_process>` doc for configuring and launching
34 IPython processes.
34 IPython processes.
35
35
36 Creating a Client
36 Creating a Client
37 =================
37 =================
38
38
39 Creating a client with default settings has not changed much, though the extended options have.
39 Creating a client with default settings has not changed much, though the extended options have.
40 One significant change is that there are no longer multiple Client classes to represent the
40 One significant change is that there are no longer multiple Client classes to represent the
41 various execution models. There is just one low-level Client object for connecting to the
41 various execution models. There is just one low-level Client object for connecting to the
42 cluster, and View objects are created from that Client that provide the different interfaces for
42 cluster, and View objects are created from that Client that provide the different interfaces for
43 execution.
43 execution.
44
44
45
45
46 To create a new client, and set up the default direct and load-balanced objects:
46 To create a new client, and set up the default direct and load-balanced objects:
47
47
48 .. sourcecode:: ipython
48 .. sourcecode:: ipython
49
49
50 # old
50 # old
51 In [1]: from IPython.kernel import client as kclient
51 In [1]: from IPython.kernel import client as kclient
52
52
53 In [2]: mec = kclient.MultiEngineClient()
53 In [2]: mec = kclient.MultiEngineClient()
54
54
55 In [3]: tc = kclient.TaskClient()
55 In [3]: tc = kclient.TaskClient()
56
56
57 # new
57 # new
58 In [1]: from IPython.parallel import Client
58 In [1]: from IPython.parallel import Client
59
59
60 In [2]: rc = Client()
60 In [2]: rc = Client()
61
61
62 In [3]: dview = rc[:]
62 In [3]: dview = rc[:]
63
63
64 In [4]: lbview = rc.load_balanced_view()
64 In [4]: lbview = rc.load_balanced_view()
65
65
66 Apply
66 Apply
67 =====
67 =====
68
68
69 The main change to the API is the addition of the :meth:`apply` to the View objects. This is a
69 The main change to the API is the addition of the :meth:`apply` to the View objects. This is a
70 method that takes `view.apply(f,*args,**kwargs)`, and calls `f(*args, **kwargs)` remotely on one
70 method that takes `view.apply(f,*args,**kwargs)`, and calls `f(*args, **kwargs)` remotely on one
71 or more engines, returning the result. This means that the natural unit of remote execution
71 or more engines, returning the result. This means that the natural unit of remote execution
72 is no longer a string of Python code, but rather a Python function.
72 is no longer a string of Python code, but rather a Python function.
73
73
74 * non-copying sends (track)
74 * non-copying sends (track)
75 * remote References
75 * remote References
76
76
77 The flags for execution have also changed. Previously, there was only `block` denoting whether
77 The flags for execution have also changed. Previously, there was only `block` denoting whether
78 to wait for results. This remains, but due to the addition of fully non-copying sends of
78 to wait for results. This remains, but due to the addition of fully non-copying sends of
79 arrays and buffers, there is also a `track` flag, which instructs PyZMQ to produce a :class:`MessageTracker` that will let you know when it is safe again to edit arrays in-place.
79 arrays and buffers, there is also a `track` flag, which instructs PyZMQ to produce a :class:`MessageTracker` that will let you know when it is safe again to edit arrays in-place.
80
80
81 The result of a non-blocking call to `apply` is now an AsyncResult_ object, described below.
81 The result of a non-blocking call to `apply` is now an AsyncResult_ object, described below.
82
82
83 MultiEngine to DirectView
83 MultiEngine to DirectView
84 =========================
84 =========================
85
85
86 The multiplexing interface previously provided by the MultiEngineClient is now provided by the
86 The multiplexing interface previously provided by the MultiEngineClient is now provided by the
87 DirectView. Once you have a Client connected, you can create a DirectView with index-access
87 DirectView. Once you have a Client connected, you can create a DirectView with index-access
88 to the client (``view = client[1:5]``). The core methods for
88 to the client (``view = client[1:5]``). The core methods for
89 communicating with engines remain: `execute`, `run`, `push`, `pull`, `scatter`, `gather`. These
89 communicating with engines remain: `execute`, `run`, `push`, `pull`, `scatter`, `gather`. These
90 methods all behave in much the same way as they did on a MultiEngineClient.
90 methods all behave in much the same way as they did on a MultiEngineClient.
91
91
92
92
93 .. sourcecode:: ipython
93 .. sourcecode:: ipython
94
94
95 # old
95 # old
96 In [2]: mec.execute('a=5', targets=[0,1,2])
96 In [2]: mec.execute('a=5', targets=[0,1,2])
97
97
98 # new
98 # new
99 In [2]: view.execute('a=5', targets=[0,1,2])
99 In [2]: view.execute('a=5', targets=[0,1,2])
100 # or
100 # or
101 In [2]: rc[0,1,2].execute('a=5')
101 In [2]: rc[0,1,2].execute('a=5')
102
102
103
103
104 This extends to any method that communicates with the engines.
104 This extends to any method that communicates with the engines.
105
105
106 Requests of the Hub (queue status, etc.) are no-longer asynchronous, and do not take a `block`
106 Requests of the Hub (queue status, etc.) are no-longer asynchronous, and do not take a `block`
107 argument.
107 argument.
108
108
109
109
110 * :meth:`get_ids` is now the property :attr:`ids`, which is passively updated by the Hub (no
110 * :meth:`get_ids` is now the property :attr:`ids`, which is passively updated by the Hub (no
111 need for network requests for an up-to-date list).
111 need for network requests for an up-to-date list).
112 * :meth:`barrier` has been renamed to :meth:`wait`, and now takes an optional timeout. :meth:`flush` is removed, as it is redundant with :meth:`wait`
112 * :meth:`barrier` has been renamed to :meth:`wait`, and now takes an optional timeout. :meth:`flush` is removed, as it is redundant with :meth:`wait`
113 * :meth:`zip_pull` has been removed
113 * :meth:`zip_pull` has been removed
114 * :meth:`keys` has been removed, but is easily implemented as::
114 * :meth:`keys` has been removed, but is easily implemented as::
115
115
116 dview.apply(lambda : globals().keys())
116 dview.apply(lambda : globals().keys())
117
117
118 * :meth:`push_function` and :meth:`push_serialized` are removed, as :meth:`push` handles
118 * :meth:`push_function` and :meth:`push_serialized` are removed, as :meth:`push` handles
119 functions without issue.
119 functions without issue.
120
120
121 .. seealso::
121 .. seealso::
122
122
123 :ref:`Our Direct Interface doc <parallel_multiengine>` for a simple tutorial with the
123 :ref:`Our Direct Interface doc <parallel_multiengine>` for a simple tutorial with the
124 DirectView.
124 DirectView.
125
125
126
126
127 The other major difference is the use of :meth:`apply`. When remote work is simply functions,
127 The other major difference is the use of :meth:`apply`. When remote work is simply functions,
128 the natural return value is the actual Python objects. It is no longer the recommended pattern
128 the natural return value is the actual Python objects. It is no longer the recommended pattern
129 to use stdout as your results, due to stream decoupling and the asynchronous nature of how the
129 to use stdout as your results, due to stream decoupling and the asynchronous nature of how the
130 stdout streams are handled in the new system.
130 stdout streams are handled in the new system.
131
131
132 Task to LoadBalancedView
132 Task to LoadBalancedView
133 ========================
133 ========================
134
134
135 Load-Balancing has changed more than Multiplexing. This is because there is no longer a notion
135 Load-Balancing has changed more than Multiplexing. This is because there is no longer a notion
136 of a StringTask or a MapTask, there are simply Python functions to call. Tasks are now
136 of a StringTask or a MapTask, there are simply Python functions to call. Tasks are now
137 simpler, because they are no longer composites of push/execute/pull/clear calls, they are
137 simpler, because they are no longer composites of push/execute/pull/clear calls, they are
138 a single function that takes arguments, and returns objects.
138 a single function that takes arguments, and returns objects.
139
139
140 The load-balanced interface is provided by the :class:`LoadBalancedView` class, created by the client:
140 The load-balanced interface is provided by the :class:`LoadBalancedView` class, created by the client:
141
141
142 .. sourcecode:: ipython
142 .. sourcecode:: ipython
143
143
144 In [10]: lbview = rc.load_balanced_view()
144 In [10]: lbview = rc.load_balanced_view()
145
145
146 # load-balancing can also be restricted to a subset of engines:
146 # load-balancing can also be restricted to a subset of engines:
147 In [10]: lbview = rc.load_balanced_view([1,2,3])
147 In [10]: lbview = rc.load_balanced_view([1,2,3])
148
148
149 A simple task would consist of sending some data, calling a function on that data, plus some
149 A simple task would consist of sending some data, calling a function on that data, plus some
150 data that was resident on the engine already, and then pulling back some results. This can
150 data that was resident on the engine already, and then pulling back some results. This can
151 all be done with a single function.
151 all be done with a single function.
152
152
153
153
154 Let's say you want to compute the dot product of two matrices, one of which resides on the
154 Let's say you want to compute the dot product of two matrices, one of which resides on the
155 engine, and another resides on the client. You might construct a task that looks like this:
155 engine, and another resides on the client. You might construct a task that looks like this:
156
156
157 .. sourcecode:: ipython
157 .. sourcecode:: ipython
158
158
159 In [10]: st = kclient.StringTask("""
159 In [10]: st = kclient.StringTask("""
160 import numpy
160 import numpy
161 C=numpy.dot(A,B)
161 C=numpy.dot(A,B)
162 """,
162 """,
163 push=dict(B=B),
163 push=dict(B=B),
164 pull='C'
164 pull='C'
165 )
165 )
166
166
167 In [11]: tid = tc.run(st)
167 In [11]: tid = tc.run(st)
168
168
169 In [12]: tr = tc.get_task_result(tid)
169 In [12]: tr = tc.get_task_result(tid)
170
170
171 In [13]: C = tc['C']
171 In [13]: C = tc['C']
172
172
173 In the new code, this is simpler:
173 In the new code, this is simpler:
174
174
175 .. sourcecode:: ipython
175 .. sourcecode:: ipython
176
176
177 In [10]: import numpy
177 In [10]: import numpy
178
178
179 In [11]: from IPython.parallel import Reference
179 In [11]: from IPython.parallel import Reference
180
180
181 In [12]: ar = lbview.apply(numpy.dot, Reference('A'), B)
181 In [12]: ar = lbview.apply(numpy.dot, Reference('A'), B)
182
182
183 In [13]: C = ar.get()
183 In [13]: C = ar.get()
184
184
185 Note the use of ``Reference`` This is a convenient representation of an object that exists
185 Note the use of ``Reference`` This is a convenient representation of an object that exists
186 in the engine's namespace, so you can pass remote objects as arguments to your task functions.
186 in the engine's namespace, so you can pass remote objects as arguments to your task functions.
187
187
188 Also note that in the kernel model, after the task is run, 'A', 'B', and 'C' are all defined on
188 Also note that in the kernel model, after the task is run, 'A', 'B', and 'C' are all defined on
189 the engine. In order to deal with this, there is also a `clear_after` flag for Tasks to prevent
189 the engine. In order to deal with this, there is also a `clear_after` flag for Tasks to prevent
190 pollution of the namespace, and bloating of engine memory. This is not necessary with the new
190 pollution of the namespace, and bloating of engine memory. This is not necessary with the new
191 code, because only those objects explicitly pushed (or set via `globals()`) will be resident on
191 code, because only those objects explicitly pushed (or set via `globals()`) will be resident on
192 the engine beyond the duration of the task.
192 the engine beyond the duration of the task.
193
193
194 .. seealso::
194 .. seealso::
195
195
196 Dependencies also work very differently than in IPython.kernel. See our :ref:`doc on Dependencies<parallel_dependencies>` for details.
196 Dependencies also work very differently than in IPython.kernel. See our :ref:`doc on Dependencies<parallel_dependencies>` for details.
197
197
198 .. seealso::
198 .. seealso::
199
199
200 :ref:`Our Task Interface doc <parallel_task>` for a simple tutorial with the
200 :ref:`Our Task Interface doc <parallel_task>` for a simple tutorial with the
201 LoadBalancedView.
201 LoadBalancedView.
202
202
203
203
204 PendingResults to AsyncResults
204 PendingResults to AsyncResults
205 ------------------------------
205 ------------------------------
206
206
207 With the departure from Twisted, we no longer have the :class:`Deferred` class for representing
207 With the departure from Twisted, we no longer have the :class:`Deferred` class for representing
208 unfinished results. For this, we have an AsyncResult object, based on the object of the same
208 unfinished results. For this, we have an AsyncResult object, based on the object of the same
209 name in the built-in :mod:`multiprocessing.pool` module. Our version provides a superset of that
209 name in the built-in :mod:`multiprocessing.pool` module. Our version provides a superset of that
210 interface.
210 interface.
211
211
212 However, unlike in IPython.kernel, we do not have PendingDeferred, PendingResult, or TaskResult
212 However, unlike in IPython.kernel, we do not have PendingDeferred, PendingResult, or TaskResult
213 objects. Simply this one object, the AsyncResult. Every asynchronous (`block=False`) call
213 objects. Simply this one object, the AsyncResult. Every asynchronous (`block=False`) call
214 returns one.
214 returns one.
215
215
216 The basic methods of an AsyncResult are:
216 The basic methods of an AsyncResult are:
217
217
218 .. sourcecode:: python
218 .. sourcecode:: python
219
219
220 AsyncResult.wait([timeout]): # wait for the result to arrive
220 AsyncResult.wait([timeout]): # wait for the result to arrive
221 AsyncResult.get([timeout]): # wait for the result to arrive, and then return it
221 AsyncResult.get([timeout]): # wait for the result to arrive, and then return it
222 AsyncResult.metadata: # dict of extra information about execution.
222 AsyncResult.metadata: # dict of extra information about execution.
223
223
224 There are still some things that behave the same as IPython.kernel:
224 There are still some things that behave the same as IPython.kernel:
225
225
226 .. sourcecode:: ipython
226 .. sourcecode:: ipython
227
227
228 # old
228 # old
229 In [5]: pr = mec.pull('a', targets=[0,1], block=False)
229 In [5]: pr = mec.pull('a', targets=[0,1], block=False)
230 In [6]: pr.r
230 In [6]: pr.r
231 Out[6]: [5, 5]
231 Out[6]: [5, 5]
232
232
233 # new
233 # new
234 In [5]: ar = dview.pull('a', targets=[0,1], block=False)
234 In [5]: ar = dview.pull('a', targets=[0,1], block=False)
235 In [6]: ar.r
235 In [6]: ar.r
236 Out[6]: [5, 5]
236 Out[6]: [5, 5]
237
237
238 The ``.r`` or ``.result`` property simply calls :meth:`get`, waiting for and returning the
238 The ``.r`` or ``.result`` property simply calls :meth:`get`, waiting for and returning the
239 result.
239 result.
240
240
241 .. seealso::
241 .. seealso::
242
242
243 :ref:`AsyncResult details <AsyncResult>`
243 :doc:`AsyncResult details <asyncresult>`
244
244
245
245
General Comments 0
You need to be logged in to leave comments. Login now