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