##// END OF EJS Templates
removing bad comma
K.-Michael Aye -
Show More
@@ -1,702 +1,702 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 `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 = rc.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 .. seealso::
391 391
392 392 See the documentation of the :ref:`Parallel Magics <parallel_magics>`.
393 393
394 394
395 395 Moving Python objects around
396 396 ============================
397 397
398 398 In addition to calling functions and executing code on engines, you can
399 399 transfer Python objects to and from your IPython session and the engines. In
400 400 IPython, these operations are called :meth:`push` (sending an object to the
401 401 engines) and :meth:`pull` (getting an object from the engines).
402 402
403 403 Basic push and pull
404 404 -------------------
405 405
406 406 Here are some examples of how you use :meth:`push` and :meth:`pull`:
407 407
408 408 .. sourcecode:: ipython
409 409
410 410 In [38]: dview.push(dict(a=1.03234,b=3453))
411 411 Out[38]: [None,None,None,None]
412 412
413 413 In [39]: dview.pull('a')
414 414 Out[39]: [ 1.03234, 1.03234, 1.03234, 1.03234]
415 415
416 416 In [40]: dview.pull('b', targets=0)
417 417 Out[40]: 3453
418 418
419 419 In [41]: dview.pull(('a','b'))
420 420 Out[41]: [ [1.03234, 3453], [1.03234, 3453], [1.03234, 3453], [1.03234, 3453] ]
421 421
422 422 In [42]: dview.push(dict(c='speed'))
423 423 Out[42]: [None,None,None,None]
424 424
425 425 In non-blocking mode :meth:`push` and :meth:`pull` also return
426 426 :class:`AsyncResult` objects:
427 427
428 428 .. sourcecode:: ipython
429 429
430 430 In [48]: ar = dview.pull('a', block=False)
431 431
432 432 In [49]: ar.get()
433 433 Out[49]: [1.03234, 1.03234, 1.03234, 1.03234]
434 434
435 435
436 436 Dictionary interface
437 437 --------------------
438 438
439 439 Since a Python namespace is just a :class:`dict`, :class:`DirectView` objects provide
440 440 dictionary-style access by key and methods such as :meth:`get` and
441 441 :meth:`update` for convenience. This make the remote namespaces of the engines
442 442 appear as a local dictionary. Underneath, these methods call :meth:`apply`:
443 443
444 444 .. sourcecode:: ipython
445 445
446 446 In [51]: dview['a']=['foo','bar']
447 447
448 448 In [52]: dview['a']
449 449 Out[52]: [ ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar'] ]
450 450
451 451 Scatter and gather
452 452 ------------------
453 453
454 454 Sometimes it is useful to partition a sequence and push the partitions to
455 455 different engines. In MPI language, this is know as scatter/gather and we
456 456 follow that terminology. However, it is important to remember that in
457 457 IPython's :class:`Client` class, :meth:`scatter` is from the
458 458 interactive IPython session to the engines and :meth:`gather` is from the
459 459 engines back to the interactive IPython session. For scatter/gather operations
460 460 between engines, MPI, pyzmq, or some other direct interconnect should be used.
461 461
462 462 .. sourcecode:: ipython
463 463
464 464 In [58]: dview.scatter('a',range(16))
465 465 Out[58]: [None,None,None,None]
466 466
467 467 In [59]: dview['a']
468 468 Out[59]: [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15] ]
469 469
470 470 In [60]: dview.gather('a')
471 471 Out[60]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
472 472
473 473 Other things to look at
474 474 =======================
475 475
476 476 How to do parallel list comprehensions
477 477 --------------------------------------
478 478
479 479 In many cases list comprehensions are nicer than using the map function. While
480 480 we don't have fully parallel list comprehensions, it is simple to get the
481 481 basic effect using :meth:`scatter` and :meth:`gather`:
482 482
483 483 .. sourcecode:: ipython
484 484
485 485 In [66]: dview.scatter('x',range(64))
486 486
487 487 In [67]: %px y = [i**10 for i in x]
488 488 Parallel execution on engines: [0, 1, 2, 3]
489 489
490 490 In [68]: y = dview.gather('y')
491 491
492 492 In [69]: print y
493 493 [0, 1, 1024, 59049, 1048576, 9765625, 60466176, 282475249, 1073741824,...]
494 494
495 495 Remote imports
496 496 --------------
497 497
498 498 Sometimes you will want to import packages both in your interactive session
499 499 and on your remote engines. This can be done with the :class:`ContextManager`
500 500 created by a DirectView's :meth:`sync_imports` method:
501 501
502 502 .. sourcecode:: ipython
503 503
504 504 In [69]: with dview.sync_imports():
505 505 ....: import numpy
506 506 importing numpy on engine(s)
507 507
508 508 Any imports made inside the block will also be performed on the view's engines.
509 509 sync_imports also takes a `local` boolean flag that defaults to True, which specifies
510 510 whether the local imports should also be performed. However, support for `local=False`
511 511 has not been implemented, so only packages that can be imported locally will work
512 this way. Note, that the usual renaming of the import handle in the same line like in
512 this way. Note that the usual renaming of the import handle in the same line like in
513 513 `import matplotlib.pyplot as plt' does not work on the remote engine, the `as plt` is
514 514 ignored remotely, while it executes locally. One could rename the remote handle with
515 515 `%px plt = pyplot` though after the import.
516 516
517 517 You can also specify imports via the ``@require`` decorator. This is a decorator
518 518 designed for use in Dependencies, but can be used to handle remote imports as well.
519 519 Modules or module names passed to ``@require`` will be imported before the decorated
520 520 function is called. If they cannot be imported, the decorated function will never
521 521 execute and will fail with an UnmetDependencyError. Failures of single Engines will
522 522 be collected and raise a CompositeError, as demonstrated in the next section.
523 523
524 524 .. sourcecode:: ipython
525 525
526 526 In [69]: from IPython.parallel import require
527 527
528 528 In [70]: @require('re')
529 529 ....: def findall(pat, x):
530 530 ....: # re is guaranteed to be available
531 531 ....: return re.findall(pat, x)
532 532
533 533 # you can also pass modules themselves, that you already have locally:
534 534 In [71]: @require(time)
535 535 ....: def wait(t):
536 536 ....: time.sleep(t)
537 537 ....: return t
538 538
539 539 .. note::
540 540
541 541 :func:`sync_imports` does not allow ``import foo as bar`` syntax,
542 542 because the assignment represented by the ``as bar`` part is not
543 543 available to the import hook.
544 544
545 545
546 546 .. _parallel_exceptions:
547 547
548 548 Parallel exceptions
549 549 -------------------
550 550
551 551 In the multiengine interface, parallel commands can raise Python exceptions,
552 552 just like serial commands. But it is a little subtle, because a single
553 553 parallel command can actually raise multiple exceptions (one for each engine
554 554 the command was run on). To express this idea, we have a
555 555 :exc:`CompositeError` exception class that will be raised in most cases. The
556 556 :exc:`CompositeError` class is a special type of exception that wraps one or
557 557 more other types of exceptions. Here is how it works:
558 558
559 559 .. sourcecode:: ipython
560 560
561 561 In [78]: dview.block = True
562 562
563 563 In [79]: dview.execute("1/0")
564 564 [0:execute]:
565 565 ---------------------------------------------------------------------------
566 566 ZeroDivisionError Traceback (most recent call last)
567 567 ----> 1 1/0
568 568 ZeroDivisionError: integer division or modulo by zero
569 569
570 570 [1:execute]:
571 571 ---------------------------------------------------------------------------
572 572 ZeroDivisionError Traceback (most recent call last)
573 573 ----> 1 1/0
574 574 ZeroDivisionError: integer division or modulo by zero
575 575
576 576 [2:execute]:
577 577 ---------------------------------------------------------------------------
578 578 ZeroDivisionError Traceback (most recent call last)
579 579 ----> 1 1/0
580 580 ZeroDivisionError: integer division or modulo by zero
581 581
582 582 [3:execute]:
583 583 ---------------------------------------------------------------------------
584 584 ZeroDivisionError Traceback (most recent call last)
585 585 ----> 1 1/0
586 586 ZeroDivisionError: integer division or modulo by zero
587 587
588 588 Notice how the error message printed when :exc:`CompositeError` is raised has
589 589 information about the individual exceptions that were raised on each engine.
590 590 If you want, you can even raise one of these original exceptions:
591 591
592 592 .. sourcecode:: ipython
593 593
594 594 In [79]: from IPython.parallel import CompositeError
595 595
596 596 In [80]: try:
597 597 ....: dview.execute('1/0', block=True)
598 598 ....: except CompositeError, e:
599 599 ....: e.raise_exception()
600 600 ....:
601 601 ....:
602 602 ---------------------------------------------------------------------------
603 603 ZeroDivisionError Traceback (most recent call last)
604 604 ----> 1 1/0
605 605 ZeroDivisionError: integer division or modulo by zero
606 606
607 607 If you are working in IPython, you can simple type ``%debug`` after one of
608 608 these :exc:`CompositeError` exceptions is raised, and inspect the exception
609 609 instance:
610 610
611 611 .. sourcecode:: ipython
612 612
613 613 In [81]: dview.execute('1/0')
614 614 [0:execute]:
615 615 ---------------------------------------------------------------------------
616 616 ZeroDivisionError Traceback (most recent call last)
617 617 ----> 1 1/0
618 618 ZeroDivisionError: integer division or modulo by zero
619 619
620 620 [1:execute]:
621 621 ---------------------------------------------------------------------------
622 622 ZeroDivisionError Traceback (most recent call last)
623 623 ----> 1 1/0
624 624 ZeroDivisionError: integer division or modulo by zero
625 625
626 626 [2:execute]:
627 627 ---------------------------------------------------------------------------
628 628 ZeroDivisionError Traceback (most recent call last)
629 629 ----> 1 1/0
630 630 ZeroDivisionError: integer division or modulo by zero
631 631
632 632 [3:execute]:
633 633 ---------------------------------------------------------------------------
634 634 ZeroDivisionError Traceback (most recent call last)
635 635 ----> 1 1/0
636 636 ZeroDivisionError: integer division or modulo by zero
637 637
638 638 In [82]: %debug
639 639 > /.../site-packages/IPython/parallel/client/asyncresult.py(125)get()
640 640 124 else:
641 641 --> 125 raise self._exception
642 642 126 else:
643 643
644 644 # Here, self._exception is the CompositeError instance:
645 645
646 646 ipdb> e = self._exception
647 647 ipdb> e
648 648 CompositeError(4)
649 649
650 650 # we can tab-complete on e to see available methods:
651 651 ipdb> e.<TAB>
652 652 e.args e.message e.traceback
653 653 e.elist e.msg
654 654 e.ename e.print_traceback
655 655 e.engine_info e.raise_exception
656 656 e.evalue e.render_traceback
657 657
658 658 # We can then display the individual tracebacks, if we want:
659 659 ipdb> e.print_traceback(1)
660 660 [1:execute]:
661 661 ---------------------------------------------------------------------------
662 662 ZeroDivisionError Traceback (most recent call last)
663 663 ----> 1 1/0
664 664 ZeroDivisionError: integer division or modulo by zero
665 665
666 666
667 667 Since you might have 100 engines, you probably don't want to see 100 tracebacks
668 668 for a simple NameError because of a typo.
669 669 For this reason, CompositeError truncates the list of exceptions it will print
670 670 to :attr:`CompositeError.tb_limit` (default is five).
671 671 You can change this limit to suit your needs with:
672 672
673 673 .. sourcecode:: ipython
674 674
675 675 In [20]: from IPython.parallel import CompositeError
676 676 In [21]: CompositeError.tb_limit = 1
677 677 In [22]: %px x=z
678 678 [0:execute]:
679 679 ---------------------------------------------------------------------------
680 680 NameError Traceback (most recent call last)
681 681 ----> 1 x=z
682 682 NameError: name 'z' is not defined
683 683
684 684 ... 3 more exceptions ...
685 685
686 686
687 687 All of this same error handling magic even works in non-blocking mode:
688 688
689 689 .. sourcecode:: ipython
690 690
691 691 In [83]: dview.block=False
692 692
693 693 In [84]: ar = dview.execute('1/0')
694 694
695 695 In [85]: ar.get()
696 696 [0:execute]:
697 697 ---------------------------------------------------------------------------
698 698 ZeroDivisionError Traceback (most recent call last)
699 699 ----> 1 1/0
700 700 ZeroDivisionError: integer division or modulo by zero
701 701
702 702 ... 3 more exceptions ...
General Comments 0
You need to be logged in to leave comments. Login now