##// END OF EJS Templates
document promoting an Engine to a regular Kernel
MinRK -
Show More
@@ -1,944 +1,1002 b''
1 1 .. _parallel_multiengine:
2 2
3 3 ==========================
4 4 IPython's Direct interface
5 5 ==========================
6 6
7 7 The direct, or multiengine, interface represents one possible way of working with a set of
8 8 IPython engines. The basic idea behind the multiengine interface is that the
9 9 capabilities of each engine are directly and explicitly exposed to the user.
10 10 Thus, in the multiengine interface, each engine is given an id that is used to
11 11 identify the engine and give it work to do. This interface is very intuitive
12 12 and is designed with interactive usage in mind, and is the best place for
13 13 new users of IPython to begin.
14 14
15 15 Starting the IPython controller and engines
16 16 ===========================================
17 17
18 18 To follow along with this tutorial, you will need to start the IPython
19 19 controller and four IPython engines. The simplest way of doing this is to use
20 20 the :command:`ipcluster` command::
21 21
22 22 $ ipcluster start -n 4
23 23
24 24 For more detailed information about starting the controller and engines, see
25 25 our :ref:`introduction <parallel_overview>` to using IPython for parallel computing.
26 26
27 27 Creating a ``DirectView`` instance
28 28 ==================================
29 29
30 30 The first step is to import the IPython :mod:`IPython.parallel`
31 31 module and then create a :class:`.Client` instance:
32 32
33 33 .. sourcecode:: ipython
34 34
35 35 In [1]: from IPython.parallel import Client
36 36
37 37 In [2]: rc = Client()
38 38
39 39 This form assumes that the default connection information (stored in
40 40 :file:`ipcontroller-client.json` found in :file:`IPYTHONDIR/profile_default/security`) is
41 41 accurate. If the controller was started on a remote machine, you must copy that connection
42 42 file to the client machine, or enter its contents as arguments to the Client constructor:
43 43
44 44 .. sourcecode:: ipython
45 45
46 46 # If you have copied the json connector file from the controller:
47 47 In [2]: rc = Client('/path/to/ipcontroller-client.json')
48 48 # or to connect with a specific profile you have set up:
49 49 In [3]: rc = Client(profile='mpi')
50 50
51 51
52 52 To make sure there are engines connected to the controller, users can get a list
53 53 of engine ids:
54 54
55 55 .. sourcecode:: ipython
56 56
57 57 In [3]: rc.ids
58 58 Out[3]: [0, 1, 2, 3]
59 59
60 60 Here we see that there are four engines ready to do work for us.
61 61
62 62 For direct execution, we will make use of a :class:`DirectView` object, which can be
63 63 constructed via list-access to the client:
64 64
65 65 .. sourcecode:: ipython
66 66
67 67 In [4]: dview = rc[:] # use all engines
68 68
69 69 .. seealso::
70 70
71 71 For more information, see the in-depth explanation of :ref:`Views <parallel_details>`.
72 72
73 73
74 74 Quick and easy parallelism
75 75 ==========================
76 76
77 77 In many cases, you simply want to apply a Python function to a sequence of
78 78 objects, but *in parallel*. The client interface provides a simple way
79 79 of accomplishing this: using the DirectView's :meth:`~DirectView.map` method.
80 80
81 81 Parallel map
82 82 ------------
83 83
84 84 Python's builtin :func:`map` functions allows a function to be applied to a
85 85 sequence element-by-element. This type of code is typically trivial to
86 86 parallelize. In fact, since IPython's interface is all about functions anyway,
87 87 you can just use the builtin :func:`map` with a :class:`RemoteFunction`, or a
88 88 DirectView's :meth:`map` method:
89 89
90 90 .. sourcecode:: ipython
91 91
92 92 In [62]: serial_result = map(lambda x:x**10, range(32))
93 93
94 94 In [63]: parallel_result = dview.map_sync(lambda x: x**10, range(32))
95 95
96 96 In [67]: serial_result==parallel_result
97 97 Out[67]: True
98 98
99 99
100 100 .. note::
101 101
102 102 The :class:`DirectView`'s version of :meth:`map` does
103 103 not do dynamic load balancing. For a load balanced version, use a
104 104 :class:`LoadBalancedView`.
105 105
106 106 .. seealso::
107 107
108 108 :meth:`map` is implemented via :class:`ParallelFunction`.
109 109
110 110 Remote function decorators
111 111 --------------------------
112 112
113 113 Remote functions are just like normal functions, but when they are called,
114 114 they execute on one or more engines, rather than locally. IPython provides
115 115 two decorators:
116 116
117 117 .. sourcecode:: ipython
118 118
119 119 In [10]: @dview.remote(block=True)
120 120 ....: def getpid():
121 121 ....: import os
122 122 ....: return os.getpid()
123 123 ....:
124 124
125 125 In [11]: getpid()
126 126 Out[11]: [12345, 12346, 12347, 12348]
127 127
128 128 The ``@parallel`` decorator creates parallel functions, that break up an element-wise
129 129 operations and distribute them, reconstructing the result.
130 130
131 131 .. sourcecode:: ipython
132 132
133 133 In [12]: import numpy as np
134 134
135 135 In [13]: A = np.random.random((64,48))
136 136
137 137 In [14]: @dview.parallel(block=True)
138 138 ....: def pmul(A,B):
139 139 ....: return A*B
140 140
141 141 In [15]: C_local = A*A
142 142
143 143 In [16]: C_remote = pmul(A,A)
144 144
145 145 In [17]: (C_local == C_remote).all()
146 146 Out[17]: True
147 147
148 148 Calling a ``@parallel`` function *does not* correspond to map. It is used for splitting
149 149 element-wise operations that operate on a sequence or array. For ``map`` behavior,
150 150 parallel functions do have a map method.
151 151
152 152 ==================== ============================ =============================
153 153 call pfunc(seq) pfunc.map(seq)
154 154 ==================== ============================ =============================
155 155 # of tasks # of engines (1 per engine) # of engines (1 per engine)
156 156 # of remote calls # of engines (1 per engine) ``len(seq)``
157 157 argument to remote ``seq[i:j]`` (sub-sequence) ``seq[i]`` (single element)
158 158 ==================== ============================ =============================
159 159
160 160 A quick example to illustrate the difference in arguments for the two modes:
161 161
162 162 .. sourcecode:: ipython
163 163
164 164 In [16]: @dview.parallel(block=True)
165 165 ....: def echo(x):
166 166 ....: return str(x)
167 167 ....:
168 168
169 169 In [17]: echo(range(5))
170 170 Out[17]: ['[0, 1]', '[2]', '[3]', '[4]']
171 171
172 172 In [18]: echo.map(range(5))
173 173 Out[18]: ['0', '1', '2', '3', '4']
174 174
175 175
176 176 .. seealso::
177 177
178 178 See the :func:`~.remotefunction.parallel` and :func:`~.remotefunction.remote`
179 179 decorators for options.
180 180
181 181 Calling Python functions
182 182 ========================
183 183
184 184 The most basic type of operation that can be performed on the engines is to
185 185 execute Python code or call Python functions. Executing Python code can be
186 186 done in blocking or non-blocking mode (non-blocking is default) using the
187 187 :meth:`.View.execute` method, and calling functions can be done via the
188 188 :meth:`.View.apply` method.
189 189
190 190 apply
191 191 -----
192 192
193 193 The main method for doing remote execution (in fact, all methods that
194 194 communicate with the engines are built on top of it), is :meth:`View.apply`.
195 195
196 196 We strive to provide the cleanest interface we can, so `apply` has the following
197 197 signature:
198 198
199 199 .. sourcecode:: python
200 200
201 201 view.apply(f, *args, **kwargs)
202 202
203 203 There are various ways to call functions with IPython, and these flags are set as
204 204 attributes of the View. The ``DirectView`` has just two of these flags:
205 205
206 206 dv.block : bool
207 207 whether to wait for the result, or return an :class:`AsyncResult` object
208 208 immediately
209 209 dv.track : bool
210 210 whether to instruct pyzmq to track when zeromq is done sending the message.
211 211 This is primarily useful for non-copying sends of numpy arrays that you plan to
212 212 edit in-place. You need to know when it becomes safe to edit the buffer
213 213 without corrupting the message.
214 214 dv.targets : int, list of ints
215 215 which targets this view is associated with.
216 216
217 217
218 218 Creating a view is simple: index-access on a client creates a :class:`.DirectView`.
219 219
220 220 .. sourcecode:: ipython
221 221
222 222 In [4]: view = rc[1:3]
223 223 Out[4]: <DirectView [1, 2]>
224 224
225 225 In [5]: view.apply<tab>
226 226 view.apply view.apply_async view.apply_sync
227 227
228 228 For convenience, you can set block temporarily for a single call with the extra sync/async methods.
229 229
230 230 Blocking execution
231 231 ------------------
232 232
233 233 In blocking mode, the :class:`.DirectView` object (called ``dview`` in
234 234 these examples) submits the command to the controller, which places the
235 235 command in the engines' queues for execution. The :meth:`apply` call then
236 236 blocks until the engines are done executing the command:
237 237
238 238 .. sourcecode:: ipython
239 239
240 240 In [2]: dview = rc[:] # A DirectView of all engines
241 241 In [3]: dview.block=True
242 242 In [4]: dview['a'] = 5
243 243
244 244 In [5]: dview['b'] = 10
245 245
246 246 In [6]: dview.apply(lambda x: a+b+x, 27)
247 247 Out[6]: [42, 42, 42, 42]
248 248
249 249 You can also select blocking execution on a call-by-call basis with the :meth:`apply_sync`
250 250 method:
251 251
252 252 .. sourcecode:: ipython
253 253
254 254 In [7]: dview.block=False
255 255
256 256 In [8]: dview.apply_sync(lambda x: a+b+x, 27)
257 257 Out[8]: [42, 42, 42, 42]
258 258
259 259 Python commands can be executed as strings on specific engines by using a View's ``execute``
260 260 method:
261 261
262 262 .. sourcecode:: ipython
263 263
264 264 In [6]: rc[::2].execute('c=a+b')
265 265
266 266 In [7]: rc[1::2].execute('c=a-b')
267 267
268 268 In [8]: dview['c'] # shorthand for dview.pull('c', block=True)
269 269 Out[8]: [15, -5, 15, -5]
270 270
271 271
272 272 Non-blocking execution
273 273 ----------------------
274 274
275 275 In non-blocking mode, :meth:`apply` submits the command to be executed and
276 276 then returns a :class:`AsyncResult` object immediately. The
277 277 :class:`AsyncResult` object gives you a way of getting a result at a later
278 278 time through its :meth:`get` method.
279 279
280 280 .. seealso::
281 281
282 282 Docs on the :ref:`AsyncResult <parallel_asyncresult>` object.
283 283
284 284 This allows you to quickly submit long running commands without blocking your
285 285 local Python/IPython session:
286 286
287 287 .. sourcecode:: ipython
288 288
289 289 # define our function
290 290 In [6]: def wait(t):
291 291 ....: import time
292 292 ....: tic = time.time()
293 293 ....: time.sleep(t)
294 294 ....: return time.time()-tic
295 295
296 296 # In non-blocking mode
297 297 In [7]: ar = dview.apply_async(wait, 2)
298 298
299 299 # Now block for the result
300 300 In [8]: ar.get()
301 301 Out[8]: [2.0006198883056641, 1.9997570514678955, 1.9996809959411621, 2.0003249645233154]
302 302
303 303 # Again in non-blocking mode
304 304 In [9]: ar = dview.apply_async(wait, 10)
305 305
306 306 # Poll to see if the result is ready
307 307 In [10]: ar.ready()
308 308 Out[10]: False
309 309
310 310 # ask for the result, but wait a maximum of 1 second:
311 311 In [45]: ar.get(1)
312 312 ---------------------------------------------------------------------------
313 313 TimeoutError Traceback (most recent call last)
314 314 /home/you/<ipython-input-45-7cd858bbb8e0> in <module>()
315 315 ----> 1 ar.get(1)
316 316
317 317 /path/to/site-packages/IPython/parallel/asyncresult.pyc in get(self, timeout)
318 318 62 raise self._exception
319 319 63 else:
320 320 ---> 64 raise error.TimeoutError("Result not ready.")
321 321 65
322 322 66 def ready(self):
323 323
324 324 TimeoutError: Result not ready.
325 325
326 326 .. Note::
327 327
328 328 Note the import inside the function. This is a common model, to ensure
329 329 that the appropriate modules are imported where the task is run. You can
330 330 also manually import modules into the engine(s) namespace(s) via
331 331 :meth:`view.execute('import numpy')`.
332 332
333 333 Often, it is desirable to wait until a set of :class:`AsyncResult` objects
334 334 are done. For this, there is a the method :meth:`wait`. This method takes a
335 335 tuple of :class:`AsyncResult` objects (or `msg_ids` or indices to the client's History),
336 336 and blocks until all of the associated results are ready:
337 337
338 338 .. sourcecode:: ipython
339 339
340 340 In [72]: dview.block=False
341 341
342 342 # A trivial list of AsyncResults objects
343 343 In [73]: pr_list = [dview.apply_async(wait, 3) for i in range(10)]
344 344
345 345 # Wait until all of them are done
346 346 In [74]: dview.wait(pr_list)
347 347
348 348 # Then, their results are ready using get() or the `.r` attribute
349 349 In [75]: pr_list[0].get()
350 350 Out[75]: [2.9982571601867676, 2.9982588291168213, 2.9987530708312988, 2.9990990161895752]
351 351
352 352
353 353
354 354 The ``block`` and ``targets`` keyword arguments and attributes
355 355 --------------------------------------------------------------
356 356
357 357 Most DirectView methods (excluding :meth:`apply`) accept ``block`` and
358 358 ``targets`` as keyword arguments. As we have seen above, these keyword arguments control the
359 359 blocking mode and which engines the command is applied to. The :class:`View` class also has
360 360 :attr:`block` and :attr:`targets` attributes that control the default behavior when the keyword
361 361 arguments are not provided. Thus the following logic is used for :attr:`block` and :attr:`targets`:
362 362
363 363 * If no keyword argument is provided, the instance attributes are used.
364 364 * The Keyword arguments, if provided overrides the instance attributes for
365 365 the duration of a single call.
366 366
367 367 The following examples demonstrate how to use the instance attributes:
368 368
369 369 .. sourcecode:: ipython
370 370
371 371 In [16]: dview.targets = [0,2]
372 372
373 373 In [17]: dview.block = False
374 374
375 375 In [18]: ar = dview.apply(lambda : 10)
376 376
377 377 In [19]: ar.get()
378 378 Out[19]: [10, 10]
379 379
380 380 In [20]: dview.targets = v.client.ids # all engines (4)
381 381
382 382 In [21]: dview.block = True
383 383
384 384 In [22]: dview.apply(lambda : 42)
385 385 Out[22]: [42, 42, 42, 42]
386 386
387 387 The :attr:`block` and :attr:`targets` instance attributes of the
388 388 :class:`.DirectView` also determine the behavior of the parallel magic commands.
389 389
390 390 Parallel magic commands
391 391 -----------------------
392 392
393 393 We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``)
394 394 that make it a bit more pleasant to execute Python commands on the engines interactively.
395 395 These are simply shortcuts to :meth:`.DirectView.execute`
396 396 and :meth:`.AsyncResult.display_outputs` methods repsectively.
397 397 The ``%px`` magic executes a single Python command on the engines
398 398 specified by the :attr:`targets` attribute of the :class:`DirectView` instance:
399 399
400 400 .. sourcecode:: ipython
401 401
402 402 # Create a DirectView for all targets
403 403 In [22]: dv = rc[:]
404 404
405 405 # Make this DirectView active for parallel magic commands
406 406 In [23]: dv.activate()
407 407
408 408 In [24]: dv.block=True
409 409
410 410 # import numpy here and everywhere
411 411 In [25]: with dv.sync_imports():
412 412 ....: import numpy
413 413 importing numpy on engine(s)
414 414
415 415 In [27]: %px a = numpy.random.rand(2,2)
416 416 Parallel execution on engines: [0, 1, 2, 3]
417 417
418 418 In [28]: %px numpy.linalg.eigvals(a)
419 419 Parallel execution on engines: [0, 1, 2, 3]
420 420 [0] Out[68]: array([ 0.77120707, -0.19448286])
421 421 [1] Out[68]: array([ 1.10815921, 0.05110369])
422 422 [2] Out[68]: array([ 0.74625527, -0.37475081])
423 423 [3] Out[68]: array([ 0.72931905, 0.07159743])
424 424
425 425 In [29]: %px print 'hi'
426 426 Parallel execution on engine(s): [0, 1, 2, 3]
427 427 [stdout:0] hi
428 428 [stdout:1] hi
429 429 [stdout:2] hi
430 430 [stdout:3] hi
431 431
432 432
433 433 Since engines are IPython as well, you can even run magics remotely:
434 434
435 435 .. sourcecode:: ipython
436 436
437 437 In [28]: %px %pylab inline
438 438 Parallel execution on engine(s): [0, 1, 2, 3]
439 439 [stdout:0]
440 440 Welcome to pylab, a matplotlib-based Python environment...
441 441 For more information, type 'help(pylab)'.
442 442 [stdout:1]
443 443 Welcome to pylab, a matplotlib-based Python environment...
444 444 For more information, type 'help(pylab)'.
445 445 [stdout:2]
446 446 Welcome to pylab, a matplotlib-based Python environment...
447 447 For more information, type 'help(pylab)'.
448 448 [stdout:3]
449 449 Welcome to pylab, a matplotlib-based Python environment...
450 450 For more information, type 'help(pylab)'.
451 451
452 452 And once in pylab mode with the inline backend,
453 453 you can make plots and they will be displayed in your frontend
454 454 if it suports the inline figures (e.g. notebook or qtconsole):
455 455
456 456 .. sourcecode:: ipython
457 457
458 458 In [40]: %px plot(rand(100))
459 459 Parallel execution on engine(s): [0, 1, 2, 3]
460 460 <plot0>
461 461 <plot1>
462 462 <plot2>
463 463 <plot3>
464 464 [0] Out[79]: [<matplotlib.lines.Line2D at 0x10a6286d0>]
465 465 [1] Out[79]: [<matplotlib.lines.Line2D at 0x10b9476d0>]
466 466 [2] Out[79]: [<matplotlib.lines.Line2D at 0x110652750>]
467 467 [3] Out[79]: [<matplotlib.lines.Line2D at 0x10c6566d0>]
468 468
469 469
470 470 ``%%px`` Cell Magic
471 471 *******************
472 472
473 473 `%%px` can also be used as a Cell Magic, which accepts ``--[no]block`` flags,
474 474 and a ``--group-outputs`` argument, which adjust how the outputs of multiple
475 475 engines are presented.
476 476
477 477 .. seealso::
478 478
479 479 :meth:`.AsyncResult.display_outputs` for the grouping options.
480 480
481 481 .. sourcecode:: ipython
482 482
483 483 In [50]: %%px --block --group-outputs=engine
484 484 ....: import numpy as np
485 485 ....: A = np.random.random((2,2))
486 486 ....: ev = numpy.linalg.eigvals(A)
487 487 ....: print ev
488 488 ....: ev.max()
489 489 ....:
490 490 Parallel execution on engine(s): [0, 1, 2, 3]
491 491 [stdout:0] [ 0.60640442 0.95919621]
492 492 [0] Out[73]: 0.9591962130899806
493 493 [stdout:1] [ 0.38501813 1.29430871]
494 494 [1] Out[73]: 1.2943087091452372
495 495 [stdout:2] [-0.85925141 0.9387692 ]
496 496 [2] Out[73]: 0.93876920456230284
497 497 [stdout:3] [ 0.37998269 1.24218246]
498 498 [3] Out[73]: 1.2421824618493817
499 499
500 500 ``%result`` Magic
501 501 *****************
502 502
503 503 If you are using ``%px`` in non-blocking mode, you won't get output.
504 504 You can use ``%result`` to display the outputs of the latest command,
505 505 just as is done when ``%px`` is blocking:
506 506
507 507 .. sourcecode:: ipython
508 508
509 509 In [39]: dv.block = False
510 510
511 511 In [40]: %px print 'hi'
512 512 Async parallel execution on engine(s): [0, 1, 2, 3]
513 513
514 514 In [41]: %result
515 515 [stdout:0] hi
516 516 [stdout:1] hi
517 517 [stdout:2] hi
518 518 [stdout:3] hi
519 519
520 520 ``%result`` simply calls :meth:`.AsyncResult.display_outputs` on the most recent request.
521 521 You can pass integers as indices if you want a result other than the latest,
522 522 e.g. ``%result -2``, or ``%result 0`` for the first.
523 523
524 524
525 525 ``%autopx``
526 526 ***********
527 527
528 528 The ``%autopx`` magic switches to a mode where everything you type is executed
529 529 on the engines until you do ``%autopx`` again.
530 530
531 531 .. sourcecode:: ipython
532 532
533 533 In [30]: dv.block=True
534 534
535 535 In [31]: %autopx
536 536 %autopx enabled
537 537
538 538 In [32]: max_evals = []
539 539
540 540 In [33]: for i in range(100):
541 541 ....: a = numpy.random.rand(10,10)
542 542 ....: a = a+a.transpose()
543 543 ....: evals = numpy.linalg.eigvals(a)
544 544 ....: max_evals.append(evals[0].real)
545 545 ....:
546 546
547 547 In [34]: print "Average max eigenvalue is: %f" % (sum(max_evals)/len(max_evals))
548 548 [stdout:0] Average max eigenvalue is: 10.193101
549 549 [stdout:1] Average max eigenvalue is: 10.064508
550 550 [stdout:2] Average max eigenvalue is: 10.055724
551 551 [stdout:3] Average max eigenvalue is: 10.086876
552
552
553 553 In [35]: %autopx
554 554 Auto Parallel Disabled
555 555
556 556
557 Engines as Kernels
558 ******************
559
560 Engines are really the same object as the Kernels used elsewhere in IPython,
561 with the minor exception that engines connect to a controller, while regular kernels
562 bind their sockets, listening for connections from a QtConsole or other frontends.
563
564 Sometimes for debugging or inspection purposes, you would like a QtConsole connected
565 to an engine for more direct interaction. You can do this by first instructing
566 the Engine to *also* bind its kernel, to listen for connections:
567
568 .. sourcecode:: ipython
569
570 In [50]: %px from IPython.parallel import bind_kernel; bind_kernel()
571
572 Then, if your engines are local, you can start a qtconsole right on the engine(s):
573
574 .. sourcecode:: ipython
575
576 In [51]: %px %qtconsole
577
578 Careful with this one, because if your view is of 16 engines it will start 16 QtConsoles!
579
580 Or you can view just the connection info, and work out the right way to connect to the engines,
581 depending on where they live and where you are:
582
583 .. sourcecode:: ipython
584
585 In [51]: %px %connect_info
586 Parallel execution on engine(s): [0, 1, 2, 3]
587 [stdout:0]
588 {
589 "stdin_port": 60387,
590 "ip": "127.0.0.1",
591 "hb_port": 50835,
592 "key": "eee2dd69-7dd3-4340-bf3e-7e2e22a62542",
593 "shell_port": 55328,
594 "iopub_port": 58264
595 }
596
597 Paste the above JSON into a file, and connect with:
598 $> ipython <app> --existing <file>
599 or, if you are local, you can connect with just:
600 $> ipython <app> --existing kernel-60125.json
601 or even just:
602 $> ipython <app> --existing
603 if this is the most recent IPython session you have started.
604 [stdout:1]
605 {
606 "stdin_port": 61869,
607 ...
608
609 .. note::
610
611 ``%qtconsole`` will call :func:`bind_kernel` on an engine if it hasn't been done already,
612 so you can often skip that first step.
613
614
557 615 Moving Python objects around
558 616 ============================
559 617
560 618 In addition to calling functions and executing code on engines, you can
561 619 transfer Python objects to and from your IPython session and the engines. In
562 620 IPython, these operations are called :meth:`push` (sending an object to the
563 621 engines) and :meth:`pull` (getting an object from the engines).
564 622
565 623 Basic push and pull
566 624 -------------------
567 625
568 626 Here are some examples of how you use :meth:`push` and :meth:`pull`:
569 627
570 628 .. sourcecode:: ipython
571 629
572 630 In [38]: dview.push(dict(a=1.03234,b=3453))
573 631 Out[38]: [None,None,None,None]
574 632
575 633 In [39]: dview.pull('a')
576 634 Out[39]: [ 1.03234, 1.03234, 1.03234, 1.03234]
577 635
578 636 In [40]: dview.pull('b', targets=0)
579 637 Out[40]: 3453
580 638
581 639 In [41]: dview.pull(('a','b'))
582 640 Out[41]: [ [1.03234, 3453], [1.03234, 3453], [1.03234, 3453], [1.03234, 3453] ]
583 641
584 642 In [42]: dview.push(dict(c='speed'))
585 643 Out[42]: [None,None,None,None]
586 644
587 645 In non-blocking mode :meth:`push` and :meth:`pull` also return
588 646 :class:`AsyncResult` objects:
589 647
590 648 .. sourcecode:: ipython
591 649
592 650 In [48]: ar = dview.pull('a', block=False)
593 651
594 652 In [49]: ar.get()
595 653 Out[49]: [1.03234, 1.03234, 1.03234, 1.03234]
596 654
597 655
598 656 Dictionary interface
599 657 --------------------
600 658
601 659 Since a Python namespace is just a :class:`dict`, :class:`DirectView` objects provide
602 660 dictionary-style access by key and methods such as :meth:`get` and
603 661 :meth:`update` for convenience. This make the remote namespaces of the engines
604 662 appear as a local dictionary. Underneath, these methods call :meth:`apply`:
605 663
606 664 .. sourcecode:: ipython
607 665
608 666 In [51]: dview['a']=['foo','bar']
609 667
610 668 In [52]: dview['a']
611 669 Out[52]: [ ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'] ]
612 670
613 671 Scatter and gather
614 672 ------------------
615 673
616 674 Sometimes it is useful to partition a sequence and push the partitions to
617 675 different engines. In MPI language, this is know as scatter/gather and we
618 676 follow that terminology. However, it is important to remember that in
619 677 IPython's :class:`Client` class, :meth:`scatter` is from the
620 678 interactive IPython session to the engines and :meth:`gather` is from the
621 679 engines back to the interactive IPython session. For scatter/gather operations
622 680 between engines, MPI, pyzmq, or some other direct interconnect should be used.
623 681
624 682 .. sourcecode:: ipython
625 683
626 684 In [58]: dview.scatter('a',range(16))
627 685 Out[58]: [None,None,None,None]
628 686
629 687 In [59]: dview['a']
630 688 Out[59]: [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15] ]
631 689
632 690 In [60]: dview.gather('a')
633 691 Out[60]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
634 692
635 693 Other things to look at
636 694 =======================
637 695
638 696 How to do parallel list comprehensions
639 697 --------------------------------------
640 698
641 699 In many cases list comprehensions are nicer than using the map function. While
642 700 we don't have fully parallel list comprehensions, it is simple to get the
643 701 basic effect using :meth:`scatter` and :meth:`gather`:
644 702
645 703 .. sourcecode:: ipython
646 704
647 705 In [66]: dview.scatter('x',range(64))
648 706
649 707 In [67]: %px y = [i**10 for i in x]
650 708 Parallel execution on engines: [0, 1, 2, 3]
651 709
652 710 In [68]: y = dview.gather('y')
653 711
654 712 In [69]: print y
655 713 [0, 1, 1024, 59049, 1048576, 9765625, 60466176, 282475249, 1073741824,...]
656 714
657 715 Remote imports
658 716 --------------
659 717
660 718 Sometimes you will want to import packages both in your interactive session
661 719 and on your remote engines. This can be done with the :class:`ContextManager`
662 720 created by a DirectView's :meth:`sync_imports` method:
663 721
664 722 .. sourcecode:: ipython
665 723
666 724 In [69]: with dview.sync_imports():
667 725 ....: import numpy
668 726 importing numpy on engine(s)
669 727
670 728 Any imports made inside the block will also be performed on the view's engines.
671 729 sync_imports also takes a `local` boolean flag that defaults to True, which specifies
672 730 whether the local imports should also be performed. However, support for `local=False`
673 731 has not been implemented, so only packages that can be imported locally will work
674 732 this way.
675 733
676 734 You can also specify imports via the ``@require`` decorator. This is a decorator
677 735 designed for use in Dependencies, but can be used to handle remote imports as well.
678 736 Modules or module names passed to ``@require`` will be imported before the decorated
679 737 function is called. If they cannot be imported, the decorated function will never
680 738 execute and will fail with an UnmetDependencyError. Failures of single Engines will
681 739 be collected and raise a CompositeError, as demonstrated in the next section.
682 740
683 741 .. sourcecode:: ipython
684 742
685 743 In [69]: from IPython.parallel import require
686 744
687 745 In [70]: @require('re'):
688 746 ....: def findall(pat, x):
689 747 ....: # re is guaranteed to be available
690 748 ....: return re.findall(pat, x)
691 749
692 750 # you can also pass modules themselves, that you already have locally:
693 751 In [71]: @require(time):
694 752 ....: def wait(t):
695 753 ....: time.sleep(t)
696 754 ....: return t
697 755
698 756 .. _parallel_exceptions:
699 757
700 758 Parallel exceptions
701 759 -------------------
702 760
703 761 In the multiengine interface, parallel commands can raise Python exceptions,
704 762 just like serial commands. But, it is a little subtle, because a single
705 763 parallel command can actually raise multiple exceptions (one for each engine
706 764 the command was run on). To express this idea, we have a
707 765 :exc:`CompositeError` exception class that will be raised in most cases. The
708 766 :exc:`CompositeError` class is a special type of exception that wraps one or
709 767 more other types of exceptions. Here is how it works:
710 768
711 769 .. sourcecode:: ipython
712 770
713 771 In [76]: dview.block=True
714 772
715 773 In [77]: dview.execute('1/0')
716 774 ---------------------------------------------------------------------------
717 775 CompositeError Traceback (most recent call last)
718 776 /home/user/<ipython-input-10-5d56b303a66c> in <module>()
719 777 ----> 1 dview.execute('1/0')
720 778
721 779 /path/to/site-packages/IPython/parallel/client/view.pyc in execute(self, code, targets, block)
722 780 591 default: self.block
723 781 592 """
724 782 --> 593 return self._really_apply(util._execute, args=(code,), block=block, targets=targets)
725 783 594
726 784 595 def run(self, filename, targets=None, block=None):
727 785
728 786 /home/user/<string> in _really_apply(self, f, args, kwargs, targets, block, track)
729 787
730 788 /path/to/site-packages/IPython/parallel/client/view.pyc in sync_results(f, self, *args, **kwargs)
731 789 55 def sync_results(f, self, *args, **kwargs):
732 790 56 """sync relevant results from self.client to our results attribute."""
733 791 ---> 57 ret = f(self, *args, **kwargs)
734 792 58 delta = self.outstanding.difference(self.client.outstanding)
735 793 59 completed = self.outstanding.intersection(delta)
736 794
737 795 /home/user/<string> in _really_apply(self, f, args, kwargs, targets, block, track)
738 796
739 797 /path/to/site-packages/IPython/parallel/client/view.pyc in save_ids(f, self, *args, **kwargs)
740 798 44 n_previous = len(self.client.history)
741 799 45 try:
742 800 ---> 46 ret = f(self, *args, **kwargs)
743 801 47 finally:
744 802 48 nmsgs = len(self.client.history) - n_previous
745 803
746 804 /path/to/site-packages/IPython/parallel/client/view.pyc in _really_apply(self, f, args, kwargs, targets, block, track)
747 805 529 if block:
748 806 530 try:
749 807 --> 531 return ar.get()
750 808 532 except KeyboardInterrupt:
751 809 533 pass
752 810
753 811 /path/to/site-packages/IPython/parallel/client/asyncresult.pyc in get(self, timeout)
754 812 101 return self._result
755 813 102 else:
756 814 --> 103 raise self._exception
757 815 104 else:
758 816 105 raise error.TimeoutError("Result not ready.")
759 817
760 818 CompositeError: one or more exceptions from call to method: _execute
761 819 [0:apply]: ZeroDivisionError: integer division or modulo by zero
762 820 [1:apply]: ZeroDivisionError: integer division or modulo by zero
763 821 [2:apply]: ZeroDivisionError: integer division or modulo by zero
764 822 [3:apply]: ZeroDivisionError: integer division or modulo by zero
765 823
766 824 Notice how the error message printed when :exc:`CompositeError` is raised has
767 825 information about the individual exceptions that were raised on each engine.
768 826 If you want, you can even raise one of these original exceptions:
769 827
770 828 .. sourcecode:: ipython
771 829
772 830 In [80]: try:
773 831 ....: dview.execute('1/0')
774 832 ....: except parallel.error.CompositeError, e:
775 833 ....: e.raise_exception()
776 834 ....:
777 835 ....:
778 836 ---------------------------------------------------------------------------
779 837 RemoteError Traceback (most recent call last)
780 838 /home/user/<ipython-input-17-8597e7e39858> in <module>()
781 839 2 dview.execute('1/0')
782 840 3 except CompositeError as e:
783 841 ----> 4 e.raise_exception()
784 842
785 843 /path/to/site-packages/IPython/parallel/error.pyc in raise_exception(self, excid)
786 844 266 raise IndexError("an exception with index %i does not exist"%excid)
787 845 267 else:
788 846 --> 268 raise RemoteError(en, ev, etb, ei)
789 847 269
790 848 270
791 849
792 850 RemoteError: ZeroDivisionError(integer division or modulo by zero)
793 851 Traceback (most recent call last):
794 852 File "/path/to/site-packages/IPython/parallel/engine/streamkernel.py", line 330, in apply_request
795 853 exec code in working,working
796 854 File "<string>", line 1, in <module>
797 855 File "/path/to/site-packages/IPython/parallel/util.py", line 354, in _execute
798 856 exec code in globals()
799 857 File "<string>", line 1, in <module>
800 858 ZeroDivisionError: integer division or modulo by zero
801 859
802 860 If you are working in IPython, you can simple type ``%debug`` after one of
803 861 these :exc:`CompositeError` exceptions is raised, and inspect the exception
804 862 instance:
805 863
806 864 .. sourcecode:: ipython
807 865
808 866 In [81]: dview.execute('1/0')
809 867 ---------------------------------------------------------------------------
810 868 CompositeError Traceback (most recent call last)
811 869 /home/user/<ipython-input-10-5d56b303a66c> in <module>()
812 870 ----> 1 dview.execute('1/0')
813 871
814 872 /path/to/site-packages/IPython/parallel/client/view.pyc in execute(self, code, targets, block)
815 873 591 default: self.block
816 874 592 """
817 875 --> 593 return self._really_apply(util._execute, args=(code,), block=block, targets=targets)
818 876 594
819 877 595 def run(self, filename, targets=None, block=None):
820 878
821 879 /home/user/<string> in _really_apply(self, f, args, kwargs, targets, block, track)
822 880
823 881 /path/to/site-packages/IPython/parallel/client/view.pyc in sync_results(f, self, *args, **kwargs)
824 882 55 def sync_results(f, self, *args, **kwargs):
825 883 56 """sync relevant results from self.client to our results attribute."""
826 884 ---> 57 ret = f(self, *args, **kwargs)
827 885 58 delta = self.outstanding.difference(self.client.outstanding)
828 886 59 completed = self.outstanding.intersection(delta)
829 887
830 888 /home/user/<string> in _really_apply(self, f, args, kwargs, targets, block, track)
831 889
832 890 /path/to/site-packages/IPython/parallel/client/view.pyc in save_ids(f, self, *args, **kwargs)
833 891 44 n_previous = len(self.client.history)
834 892 45 try:
835 893 ---> 46 ret = f(self, *args, **kwargs)
836 894 47 finally:
837 895 48 nmsgs = len(self.client.history) - n_previous
838 896
839 897 /path/to/site-packages/IPython/parallel/client/view.pyc in _really_apply(self, f, args, kwargs, targets, block, track)
840 898 529 if block:
841 899 530 try:
842 900 --> 531 return ar.get()
843 901 532 except KeyboardInterrupt:
844 902 533 pass
845 903
846 904 /path/to/site-packages/IPython/parallel/client/asyncresult.pyc in get(self, timeout)
847 905 101 return self._result
848 906 102 else:
849 907 --> 103 raise self._exception
850 908 104 else:
851 909 105 raise error.TimeoutError("Result not ready.")
852 910
853 911 CompositeError: one or more exceptions from call to method: _execute
854 912 [0:apply]: ZeroDivisionError: integer division or modulo by zero
855 913 [1:apply]: ZeroDivisionError: integer division or modulo by zero
856 914 [2:apply]: ZeroDivisionError: integer division or modulo by zero
857 915 [3:apply]: ZeroDivisionError: integer division or modulo by zero
858 916
859 917 In [82]: %debug
860 918 > /path/to/site-packages/IPython/parallel/client/asyncresult.py(103)get()
861 919 102 else:
862 920 --> 103 raise self._exception
863 921 104 else:
864 922
865 923 # With the debugger running, self._exception is the exceptions instance. We can tab complete
866 924 # on it and see the extra methods that are available.
867 925 ipdb> self._exception.<tab>
868 926 e.__class__ e.__getitem__ e.__new__ e.__setstate__ e.args
869 927 e.__delattr__ e.__getslice__ e.__reduce__ e.__str__ e.elist
870 928 e.__dict__ e.__hash__ e.__reduce_ex__ e.__weakref__ e.message
871 929 e.__doc__ e.__init__ e.__repr__ e._get_engine_str e.print_tracebacks
872 930 e.__getattribute__ e.__module__ e.__setattr__ e._get_traceback e.raise_exception
873 931 ipdb> self._exception.print_tracebacks()
874 932 [0:apply]:
875 933 Traceback (most recent call last):
876 934 File "/path/to/site-packages/IPython/parallel/engine/streamkernel.py", line 330, in apply_request
877 935 exec code in working,working
878 936 File "<string>", line 1, in <module>
879 937 File "/path/to/site-packages/IPython/parallel/util.py", line 354, in _execute
880 938 exec code in globals()
881 939 File "<string>", line 1, in <module>
882 940 ZeroDivisionError: integer division or modulo by zero
883 941
884 942
885 943 [1:apply]:
886 944 Traceback (most recent call last):
887 945 File "/path/to/site-packages/IPython/parallel/engine/streamkernel.py", line 330, in apply_request
888 946 exec code in working,working
889 947 File "<string>", line 1, in <module>
890 948 File "/path/to/site-packages/IPython/parallel/util.py", line 354, in _execute
891 949 exec code in globals()
892 950 File "<string>", line 1, in <module>
893 951 ZeroDivisionError: integer division or modulo by zero
894 952
895 953
896 954 [2:apply]:
897 955 Traceback (most recent call last):
898 956 File "/path/to/site-packages/IPython/parallel/engine/streamkernel.py", line 330, in apply_request
899 957 exec code in working,working
900 958 File "<string>", line 1, in <module>
901 959 File "/path/to/site-packages/IPython/parallel/util.py", line 354, in _execute
902 960 exec code in globals()
903 961 File "<string>", line 1, in <module>
904 962 ZeroDivisionError: integer division or modulo by zero
905 963
906 964
907 965 [3:apply]:
908 966 Traceback (most recent call last):
909 967 File "/path/to/site-packages/IPython/parallel/engine/streamkernel.py", line 330, in apply_request
910 968 exec code in working,working
911 969 File "<string>", line 1, in <module>
912 970 File "/path/to/site-packages/IPython/parallel/util.py", line 354, in _execute
913 971 exec code in globals()
914 972 File "<string>", line 1, in <module>
915 973 ZeroDivisionError: integer division or modulo by zero
916 974
917 975
918 976 All of this same error handling magic even works in non-blocking mode:
919 977
920 978 .. sourcecode:: ipython
921 979
922 980 In [83]: dview.block=False
923 981
924 982 In [84]: ar = dview.execute('1/0')
925 983
926 984 In [85]: ar.get()
927 985 ---------------------------------------------------------------------------
928 986 CompositeError Traceback (most recent call last)
929 987 /home/user/<ipython-input-21-8531eb3d26fb> in <module>()
930 988 ----> 1 ar.get()
931 989
932 990 /path/to/site-packages/IPython/parallel/client/asyncresult.pyc in get(self, timeout)
933 991 101 return self._result
934 992 102 else:
935 993 --> 103 raise self._exception
936 994 104 else:
937 995 105 raise error.TimeoutError("Result not ready.")
938 996
939 997 CompositeError: one or more exceptions from call to method: _execute
940 998 [0:apply]: ZeroDivisionError: integer division or modulo by zero
941 999 [1:apply]: ZeroDivisionError: integer division or modulo by zero
942 1000 [2:apply]: ZeroDivisionError: integer division or modulo by zero
943 1001 [3:apply]: ZeroDivisionError: integer division or modulo by zero
944 1002
General Comments 0
You need to be logged in to leave comments. Login now