##// END OF EJS Templates
Merge pull request #1768 from minrk/parallelmagics...
Fernando Perez -
r7060:a1360828 merge
parent child Browse files
Show More
@@ -0,0 +1,342 b''
1 # -*- coding: utf-8 -*-
2 """Test Parallel magics
3
4 Authors:
5
6 * Min RK
7 """
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 #-------------------------------------------------------------------------------
16 # Imports
17 #-------------------------------------------------------------------------------
18
19 import sys
20 import time
21
22 import zmq
23 from nose import SkipTest
24
25 from IPython.testing import decorators as dec
26 from IPython.testing.ipunittest import ParametricTestCase
27
28 from IPython import parallel as pmod
29 from IPython.parallel import error
30 from IPython.parallel import AsyncResult
31 from IPython.parallel.util import interactive
32
33 from IPython.parallel.tests import add_engines
34
35 from .clienttest import ClusterTestCase, capture_output, generate_output
36
37 def setup():
38 add_engines(3, total=True)
39
40 class TestParallelMagics(ClusterTestCase, ParametricTestCase):
41
42 def test_px_blocking(self):
43 ip = get_ipython()
44 v = self.client[-1:]
45 v.activate()
46 v.block=True
47
48 ip.magic('px a=5')
49 self.assertEquals(v['a'], [5])
50 ip.magic('px a=10')
51 self.assertEquals(v['a'], [10])
52 # just 'print a' works ~99% of the time, but this ensures that
53 # the stdout message has arrived when the result is finished:
54 with capture_output() as io:
55 ip.magic(
56 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
57 )
58 out = io.stdout
59 self.assertTrue('[stdout:' in out, out)
60 self.assertTrue(out.rstrip().endswith('10'))
61 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
62
63 def test_cellpx_block_args(self):
64 """%%px --[no]block flags work"""
65 ip = get_ipython()
66 v = self.client[-1:]
67 v.activate()
68 v.block=False
69
70 for block in (True, False):
71 v.block = block
72
73 with capture_output() as io:
74 ip.run_cell_magic("px", "", "1")
75 if block:
76 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
77 else:
78 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
79
80 with capture_output() as io:
81 ip.run_cell_magic("px", "--block", "1")
82 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
83
84 with capture_output() as io:
85 ip.run_cell_magic("px", "--noblock", "1")
86 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
87
88 def test_cellpx_groupby_engine(self):
89 """%%px --group-outputs=engine"""
90 ip = get_ipython()
91 v = self.client[:]
92 v.block = True
93 v.activate()
94
95 v['generate_output'] = generate_output
96
97 with capture_output() as io:
98 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
99
100 lines = io.stdout.strip().splitlines()[1:]
101 expected = [
102 ('[stdout:', '] stdout'),
103 'stdout2',
104 'IPython.core.display.HTML',
105 'IPython.core.display.Math',
106 ('] Out[', 'IPython.core.display.Math')
107 ] * len(v)
108
109 self.assertEquals(len(lines), len(expected), io.stdout)
110 for line,expect in zip(lines, expected):
111 if isinstance(expect, str):
112 expect = [expect]
113 for ex in expect:
114 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
115
116 expected = [
117 ('[stderr:', '] stderr'),
118 'stderr2',
119 ] * len(v)
120
121 lines = io.stderr.strip().splitlines()
122 self.assertEquals(len(lines), len(expected), io.stderr)
123 for line,expect in zip(lines, expected):
124 if isinstance(expect, str):
125 expect = [expect]
126 for ex in expect:
127 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
128
129
130 def test_cellpx_groupby_order(self):
131 """%%px --group-outputs=order"""
132 ip = get_ipython()
133 v = self.client[:]
134 v.block = True
135 v.activate()
136
137 v['generate_output'] = generate_output
138
139 with capture_output() as io:
140 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
141
142 lines = io.stdout.strip().splitlines()[1:]
143 expected = []
144 expected.extend([
145 ('[stdout:', '] stdout'),
146 'stdout2',
147 ] * len(v))
148 expected.extend([
149 'IPython.core.display.HTML',
150 ] * len(v))
151 expected.extend([
152 'IPython.core.display.Math',
153 ] * len(v))
154 expected.extend([
155 ('] Out[', 'IPython.core.display.Math')
156 ] * len(v))
157
158 self.assertEquals(len(lines), len(expected), io.stdout)
159 for line,expect in zip(lines, expected):
160 if isinstance(expect, str):
161 expect = [expect]
162 for ex in expect:
163 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
164
165 expected = [
166 ('[stderr:', '] stderr'),
167 'stderr2',
168 ] * len(v)
169
170 lines = io.stderr.strip().splitlines()
171 self.assertEquals(len(lines), len(expected), io.stderr)
172 for line,expect in zip(lines, expected):
173 if isinstance(expect, str):
174 expect = [expect]
175 for ex in expect:
176 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
177
178 def test_cellpx_groupby_atype(self):
179 """%%px --group-outputs=type"""
180 ip = get_ipython()
181 v = self.client[:]
182 v.block = True
183 v.activate()
184
185 v['generate_output'] = generate_output
186
187 with capture_output() as io:
188 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
189
190 lines = io.stdout.strip().splitlines()[1:]
191
192 expected = []
193 expected.extend([
194 ('[stdout:', '] stdout'),
195 'stdout2',
196 ] * len(v))
197 expected.extend([
198 'IPython.core.display.HTML',
199 'IPython.core.display.Math',
200 ] * len(v))
201 expected.extend([
202 ('] Out[', 'IPython.core.display.Math')
203 ] * len(v))
204
205 self.assertEquals(len(lines), len(expected), io.stdout)
206 for line,expect in zip(lines, expected):
207 if isinstance(expect, str):
208 expect = [expect]
209 for ex in expect:
210 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
211
212 expected = [
213 ('[stderr:', '] stderr'),
214 'stderr2',
215 ] * len(v)
216
217 lines = io.stderr.strip().splitlines()
218 self.assertEquals(len(lines), len(expected), io.stderr)
219 for line,expect in zip(lines, expected):
220 if isinstance(expect, str):
221 expect = [expect]
222 for ex in expect:
223 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
224
225
226 def test_px_nonblocking(self):
227 ip = get_ipython()
228 v = self.client[-1:]
229 v.activate()
230 v.block=False
231
232 ip.magic('px a=5')
233 self.assertEquals(v['a'], [5])
234 ip.magic('px a=10')
235 self.assertEquals(v['a'], [10])
236 with capture_output() as io:
237 ar = ip.magic('px print (a)')
238 self.assertTrue(isinstance(ar, AsyncResult))
239 self.assertTrue('Async' in io.stdout)
240 self.assertFalse('[stdout:' in io.stdout)
241 ar = ip.magic('px 1/0')
242 self.assertRaisesRemote(ZeroDivisionError, ar.get)
243
244 def test_autopx_blocking(self):
245 ip = get_ipython()
246 v = self.client[-1]
247 v.activate()
248 v.block=True
249
250 with capture_output() as io:
251 ip.magic('autopx')
252 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
253 ip.run_cell('b*=2')
254 ip.run_cell('print (b)')
255 ip.run_cell('b')
256 ip.run_cell("b/c")
257 ip.magic('autopx')
258
259 output = io.stdout.strip()
260
261 self.assertTrue(output.startswith('%autopx enabled'), output)
262 self.assertTrue(output.endswith('%autopx disabled'), output)
263 self.assertTrue('RemoteError: ZeroDivisionError' in output, output)
264 self.assertTrue('] Out[' in output, output)
265 self.assertTrue(': 24690' in output, output)
266 ar = v.get_result(-1)
267 self.assertEquals(v['a'], 5)
268 self.assertEquals(v['b'], 24690)
269 self.assertRaisesRemote(ZeroDivisionError, ar.get)
270
271 def test_autopx_nonblocking(self):
272 ip = get_ipython()
273 v = self.client[-1]
274 v.activate()
275 v.block=False
276
277 with capture_output() as io:
278 ip.magic('autopx')
279 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
280 ip.run_cell('print (b)')
281 ip.run_cell('import time; time.sleep(0.1)')
282 ip.run_cell("b/c")
283 ip.run_cell('b*=2')
284 ip.magic('autopx')
285
286 output = io.stdout.strip()
287
288 self.assertTrue(output.startswith('%autopx enabled'))
289 self.assertTrue(output.endswith('%autopx disabled'))
290 self.assertFalse('ZeroDivisionError' in output)
291 ar = v.get_result(-2)
292 self.assertRaisesRemote(ZeroDivisionError, ar.get)
293 # prevent TaskAborted on pulls, due to ZeroDivisionError
294 time.sleep(0.5)
295 self.assertEquals(v['a'], 5)
296 # b*=2 will not fire, due to abort
297 self.assertEquals(v['b'], 10)
298
299 def test_result(self):
300 ip = get_ipython()
301 v = self.client[-1]
302 v.activate()
303 data = dict(a=111,b=222)
304 v.push(data, block=True)
305
306 ip.magic('px a')
307 ip.magic('px b')
308 for idx, name in [
309 ('', 'b'),
310 ('-1', 'b'),
311 ('2', 'b'),
312 ('1', 'a'),
313 ('-2', 'a'),
314 ]:
315 with capture_output() as io:
316 ip.magic('result ' + idx)
317 output = io.stdout.strip()
318 msg = "expected %s output to include %s, but got: %s" % \
319 ('%result '+idx, str(data[name]), output)
320 self.assertTrue(str(data[name]) in output, msg)
321
322 @dec.skipif_not_matplotlib
323 def test_px_pylab(self):
324 """%pylab works on engines"""
325 ip = get_ipython()
326 v = self.client[-1]
327 v.block = True
328 v.activate()
329
330 with capture_output() as io:
331 ip.magic("px %pylab inline")
332
333 self.assertTrue("Welcome to pylab" in io.stdout, io.stdout)
334 self.assertTrue("backend_inline" in io.stdout, io.stdout)
335
336 with capture_output() as io:
337 ip.magic("px plot(rand(100))")
338
339 self.assertTrue('] Out[' in io.stdout, io.stdout)
340 self.assertTrue('matplotlib.lines' in io.stdout, io.stdout)
341
342
@@ -0,0 +1,228 b''
1 {
2 "metadata": {
3 "name": "Parallel Magics"
4 },
5 "nbformat": 3,
6 "worksheets": [
7 {
8 "cells": [
9 {
10 "cell_type": "heading",
11 "level": 1,
12 "source": [
13 "Using Parallel Magics"
14 ]
15 },
16 {
17 "cell_type": "markdown",
18 "source": [
19 "IPython has a few magics for working with your engines.",
20 "",
21 "This assumes you have started an IPython cluster, either with the notebook interface,",
22 "or the `ipcluster/controller/engine` commands."
23 ]
24 },
25 {
26 "cell_type": "code",
27 "collapsed": false,
28 "input": [
29 "from IPython import parallel",
30 "rc = parallel.Client()",
31 "dv = rc[:]",
32 "dv.block = True",
33 "dv"
34 ],
35 "language": "python",
36 "outputs": []
37 },
38 {
39 "cell_type": "markdown",
40 "source": [
41 "The parallel magics come from the `parallelmagics` IPython extension.",
42 "The magics are set to work with a particular View object,",
43 "so to activate them, you call the `activate()` method on a particular view:"
44 ]
45 },
46 {
47 "cell_type": "code",
48 "collapsed": true,
49 "input": [
50 "dv.activate()"
51 ],
52 "language": "python",
53 "outputs": []
54 },
55 {
56 "cell_type": "markdown",
57 "source": [
58 "Now we can execute code remotely with `%px`:"
59 ]
60 },
61 {
62 "cell_type": "code",
63 "collapsed": false,
64 "input": [
65 "%px a=5"
66 ],
67 "language": "python",
68 "outputs": []
69 },
70 {
71 "cell_type": "code",
72 "collapsed": false,
73 "input": [
74 "%px print a"
75 ],
76 "language": "python",
77 "outputs": []
78 },
79 {
80 "cell_type": "code",
81 "collapsed": false,
82 "input": [
83 "%px a"
84 ],
85 "language": "python",
86 "outputs": []
87 },
88 {
89 "cell_type": "markdown",
90 "source": [
91 "You don't have to wait for results:"
92 ]
93 },
94 {
95 "cell_type": "code",
96 "collapsed": true,
97 "input": [
98 "dv.block = False"
99 ],
100 "language": "python",
101 "outputs": []
102 },
103 {
104 "cell_type": "code",
105 "collapsed": false,
106 "input": [
107 "%px import time",
108 "%px time.sleep(5)",
109 "%px time.time()"
110 ],
111 "language": "python",
112 "outputs": []
113 },
114 {
115 "cell_type": "markdown",
116 "source": [
117 "But you will notice that this didn't output the result of the last command.",
118 "For this, we have `%result`, which displays the output of the latest request:"
119 ]
120 },
121 {
122 "cell_type": "code",
123 "collapsed": false,
124 "input": [
125 "%result"
126 ],
127 "language": "python",
128 "outputs": []
129 },
130 {
131 "cell_type": "markdown",
132 "source": [
133 "Remember, an IPython engine is IPython, so you can do magics remotely as well!"
134 ]
135 },
136 {
137 "cell_type": "code",
138 "collapsed": false,
139 "input": [
140 "dv.block = True",
141 "%px %pylab inline"
142 ],
143 "language": "python",
144 "outputs": []
145 },
146 {
147 "cell_type": "markdown",
148 "source": [
149 "`%%px` can also be used as a cell magic, for submitting whole blocks.",
150 "This one acceps `--block` and `--noblock` flags to specify",
151 "the blocking behavior, though the default is unchanged.",
152 ""
153 ]
154 },
155 {
156 "cell_type": "code",
157 "collapsed": true,
158 "input": [
159 "dv.scatter('id', dv.targets, flatten=True)",
160 "dv['stride'] = len(dv)"
161 ],
162 "language": "python",
163 "outputs": []
164 },
165 {
166 "cell_type": "code",
167 "collapsed": false,
168 "input": [
169 "%%px --noblock",
170 "x = linspace(0,pi,1000)",
171 "for n in range(id,12, stride):",
172 " print n",
173 " plt.plot(x,sin(n*x))",
174 "plt.title(\"Plot %i\" % id)"
175 ],
176 "language": "python",
177 "outputs": []
178 },
179 {
180 "cell_type": "code",
181 "collapsed": false,
182 "input": [
183 "%result"
184 ],
185 "language": "python",
186 "outputs": []
187 },
188 {
189 "cell_type": "markdown",
190 "source": [
191 "It also lets you choose some amount of the grouping of the outputs with `--group-outputs`:",
192 "",
193 "The choices are:",
194 "",
195 "* `engine` - all of an engine's output is collected together",
196 "* `type` - where stdout of each engine is grouped, etc. (the default)",
197 "* `order` - same as `type`, but individual displaypub outputs are interleaved.",
198 " That is, it will output the first plot from each engine, then the second from each,",
199 " etc."
200 ]
201 },
202 {
203 "cell_type": "code",
204 "collapsed": false,
205 "input": [
206 "%%px --group-outputs=engine",
207 "x = linspace(0,pi,1000)",
208 "for n in range(id,12, stride):",
209 " print n",
210 " plt.plot(x,sin(n*x))",
211 "plt.title(\"Plot %i\" % id)"
212 ],
213 "language": "python",
214 "outputs": []
215 },
216 {
217 "cell_type": "code",
218 "collapsed": true,
219 "input": [
220 ""
221 ],
222 "language": "python",
223 "outputs": []
224 }
225 ]
226 }
227 ]
228 } No newline at end of file
@@ -542,7 +542,7 b' class Magics(object):'
542 argv = arg_split(arg_str, posix, strict)
542 argv = arg_split(arg_str, posix, strict)
543 # Do regular option processing
543 # Do regular option processing
544 try:
544 try:
545 opts,args = getopt(argv,opt_str,*long_opts)
545 opts,args = getopt(argv, opt_str, long_opts)
546 except GetoptError,e:
546 except GetoptError,e:
547 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
547 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
548 " ".join(long_opts)))
548 " ".join(long_opts)))
@@ -69,6 +69,15 b' def test_magic_parse_options():'
69 expected = path
69 expected = path
70 nt.assert_equals(opts['f'], expected)
70 nt.assert_equals(opts['f'], expected)
71
71
72 def test_magic_parse_long_options():
73 """Magic.parse_options can handle --foo=bar long options"""
74 ip = get_ipython()
75 m = DummyMagics(ip)
76 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
77 nt.assert_true('foo' in opts)
78 nt.assert_true('bar' in opts)
79 nt.assert_true(opts['bar'], "bubble")
80
72
81
73 @dec.skip_without('sqlite3')
82 @dec.skip_without('sqlite3')
74 def doctest_hist_f():
83 def doctest_hist_f():
@@ -11,15 +11,15 b' Usage'
11
11
12 ``%autopx``
12 ``%autopx``
13
13
14 @AUTOPX_DOC@
14 {AUTOPX_DOC}
15
15
16 ``%px``
16 ``%px``
17
17
18 @PX_DOC@
18 {PX_DOC}
19
19
20 ``%result``
20 ``%result``
21
21
22 @RESULT_DOC@
22 {RESULT_DOC}
23
23
24 """
24 """
25
25
@@ -37,87 +37,172 b' Usage'
37 import ast
37 import ast
38 import re
38 import re
39
39
40 from IPython.core.magic import Magics, magics_class, line_magic
40 from IPython.core.error import UsageError
41 from IPython.core.magic import Magics, magics_class, line_magic, cell_magic
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.testing.skipdoctest import skip_doctest
42
43
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44 # Definitions of magic functions for use with IPython
45 # Definitions of magic functions for use with IPython
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46
47
47 NO_ACTIVE_VIEW = """
48
48 Use activate() on a DirectView object to activate it for magics.
49 NO_ACTIVE_VIEW = "Use activate() on a DirectView object to use it with magics."
49 """
50
50
51
51
52 @magics_class
52 @magics_class
53 class ParallelMagics(Magics):
53 class ParallelMagics(Magics):
54 """A set of magics useful when controlling a parallel IPython cluster.
54 """A set of magics useful when controlling a parallel IPython cluster.
55 """
55 """
56
56
57 def __init__(self, shell):
57 # A flag showing if autopx is activated or not
58 super(ParallelMagics, self).__init__(shell)
58 _autopx = False
59 # A flag showing if autopx is activated or not
59 # the current view used by the magics:
60 self.autopx = False
60 active_view = None
61
61
62 @skip_doctest
62 @skip_doctest
63 @line_magic
63 @line_magic
64 def result(self, parameter_s=''):
64 def result(self, parameter_s=''):
65 """Print the result of command i on all engines..
65 """Print the result of command i on all engines.
66
66
67 To use this a :class:`DirectView` instance must be created
67 To use this a :class:`DirectView` instance must be created
68 and then activated by calling its :meth:`activate` method.
68 and then activated by calling its :meth:`activate` method.
69
70 This lets you recall the results of %px computations after
71 asynchronous submission (view.block=False).
69
72
70 Then you can do the following::
73 Then you can do the following::
71
74
72 In [23]: %result
75 In [23]: %px os.getpid()
73 Out[23]:
76 Async parallel execution on engine(s): all
74 <Results List>
77
75 [0] In [6]: a = 10
78 In [24]: %result
76 [1] In [6]: a = 10
79 [ 8] Out[10]: 60920
77
80 [ 9] Out[10]: 60921
78 In [22]: %result 6
81 [10] Out[10]: 60922
79 Out[22]:
82 [11] Out[10]: 60923
80 <Results List>
81 [0] In [6]: a = 10
82 [1] In [6]: a = 10
83 """
83 """
84
84 if self.active_view is None:
85 if self.active_view is None:
85 print NO_ACTIVE_VIEW
86 raise UsageError(NO_ACTIVE_VIEW)
86 return
87
87
88 stride = len(self.active_view)
88 try:
89 try:
89 index = int(parameter_s)
90 index = int(parameter_s)
90 except:
91 except:
91 index = None
92 index = -1
92 result = self.active_view.get_result(index)
93 msg_ids = self.active_view.history[stride * index:(stride * (index + 1)) or None]
93 return result
94
95 result = self.active_view.get_result(msg_ids)
96
97 result.get()
98 result.display_outputs()
94
99
95 @skip_doctest
100 @skip_doctest
96 @line_magic
101 @line_magic
97 def px(self, parameter_s=''):
102 def px(self, parameter_s=''):
98 """Executes the given python command in parallel.
103 """Executes the given python command in parallel.
99
104
100 To use this a :class:`DirectView` instance must be created
105 To use this a :class:`DirectView` instance must be created
101 and then activated by calling its :meth:`activate` method.
106 and then activated by calling its :meth:`activate` method.
102
107
103 Then you can do the following::
108 Then you can do the following::
104
109
105 In [24]: %px a = 5
110 In [24]: %px a = os.getpid()
106 Parallel execution on engine(s): all
111 Parallel execution on engine(s): all
107 Out[24]:
112
108 <Results List>
113 In [25]: %px print a
109 [0] In [7]: a = 5
114 [stdout:0] 1234
110 [1] In [7]: a = 5
115 [stdout:1] 1235
116 [stdout:2] 1236
117 [stdout:3] 1237
111 """
118 """
119 return self.parallel_execute(parameter_s)
120
121 def parallel_execute(self, cell, block=None, groupby='type'):
122 """implementation used by %px and %%parallel"""
112
123
113 if self.active_view is None:
124 if self.active_view is None:
114 print NO_ACTIVE_VIEW
125 raise UsageError(NO_ACTIVE_VIEW)
115 return
126
116 print "Parallel execution on engine(s): %s" % self.active_view.targets
127 # defaults:
117 result = self.active_view.execute(parameter_s, block=False)
128 block = self.active_view.block if block is None else block
118 if self.active_view.block:
129
130 base = "Parallel" if block else "Async parallel"
131 print base + " execution on engine(s): %s" % self.active_view.targets
132
133 result = self.active_view.execute(cell, silent=False, block=False)
134 if block:
119 result.get()
135 result.get()
120 self._maybe_display_output(result)
136 result.display_outputs(groupby)
137 else:
138 # return AsyncResult only on non-blocking submission
139 return result
140
141 @skip_doctest
142 @cell_magic('px')
143 def cell_px(self, line='', cell=None):
144 """Executes the given python command in parallel.
145
146 Cell magic usage:
147
148 %%px [-o] [-e] [--group-options=type|engine|order] [--[no]block]
149
150 Options (%%px cell magic only):
151
152 -o: collate outputs in oder (same as group-outputs=order)
153
154 -e: group outputs by engine (same as group-outputs=engine)
155
156 --group-outputs=type [default behavior]:
157 each output type (stdout, stderr, displaypub) for all engines
158 displayed together.
159
160 --group-outputs=order:
161 The same as 'type', but individual displaypub outputs (e.g. plots)
162 will be interleaved, so it will display all of the first plots,
163 then all of the second plots, etc.
164
165 --group-outputs=engine:
166 All of an engine's output is displayed before moving on to the next.
167
168 --[no]block:
169 Whether or not to block for the execution to complete
170 (and display the results). If unspecified, the active view's
171
172
173 To use this a :class:`DirectView` instance must be created
174 and then activated by calling its :meth:`activate` method.
175
176 Then you can do the following::
177
178 In [24]: %%parallel --noblock a = os.getpid()
179 Async parallel execution on engine(s): all
180
181 In [25]: %px print a
182 [stdout:0] 1234
183 [stdout:1] 1235
184 [stdout:2] 1236
185 [stdout:3] 1237
186 """
187
188 block = None
189 groupby = 'type'
190 # as a cell magic, we accept args
191 opts, _ = self.parse_options(line, 'oe', 'group-outputs=', 'block', 'noblock')
192
193 if 'group-outputs' in opts:
194 groupby = opts['group-outputs']
195 elif 'o' in opts:
196 groupby = 'order'
197 elif 'e' in opts:
198 groupby = 'engine'
199
200 if 'block' in opts:
201 block = True
202 elif 'noblock' in opts:
203 block = False
204
205 return self.parallel_execute(cell, block=block, groupby=groupby)
121
206
122 @skip_doctest
207 @skip_doctest
123 @line_magic
208 @line_magic
@@ -149,7 +234,7 b' class ParallelMagics(Magics):'
149 In [27]: %autopx
234 In [27]: %autopx
150 %autopx disabled
235 %autopx disabled
151 """
236 """
152 if self.autopx:
237 if self._autopx:
153 self._disable_autopx()
238 self._disable_autopx()
154 else:
239 else:
155 self._enable_autopx()
240 self._enable_autopx()
@@ -159,50 +244,23 b' class ParallelMagics(Magics):'
159 pxrun_cell.
244 pxrun_cell.
160 """
245 """
161 if self.active_view is None:
246 if self.active_view is None:
162 print NO_ACTIVE_VIEW
247 raise UsageError(NO_ACTIVE_VIEW)
163 return
164
248
165 # override run_cell and run_code
249 # override run_cell
166 self._original_run_cell = self.shell.run_cell
250 self._original_run_cell = self.shell.run_cell
167 self.shell.run_cell = self.pxrun_cell
251 self.shell.run_cell = self.pxrun_cell
168 self._original_run_code = self.shell.run_code
169 self.shell.run_code = self.pxrun_code
170
252
171 self.autopx = True
253 self._autopx = True
172 print "%autopx enabled"
254 print "%autopx enabled"
173
255
174 def _disable_autopx(self):
256 def _disable_autopx(self):
175 """Disable %autopx by restoring the original InteractiveShell.run_cell.
257 """Disable %autopx by restoring the original InteractiveShell.run_cell.
176 """
258 """
177 if self.autopx:
259 if self._autopx:
178 self.shell.run_cell = self._original_run_cell
260 self.shell.run_cell = self._original_run_cell
179 self.shell.run_code = self._original_run_code
261 self._autopx = False
180 self.autopx = False
181 print "%autopx disabled"
262 print "%autopx disabled"
182
263
183 def _maybe_display_output(self, result):
184 """Maybe display the output of a parallel result.
185
186 If self.active_view.block is True, wait for the result
187 and display the result. Otherwise, this is a noop.
188 """
189 if isinstance(result.stdout, basestring):
190 # single result
191 stdouts = [result.stdout.rstrip()]
192 else:
193 stdouts = [s.rstrip() for s in result.stdout]
194
195 targets = self.active_view.targets
196 if isinstance(targets, int):
197 targets = [targets]
198 elif targets == 'all':
199 targets = self.active_view.client.ids
200
201 if any(stdouts):
202 for eid,stdout in zip(targets, stdouts):
203 print '[stdout:%i]'%eid, stdout
204
205
206 def pxrun_cell(self, raw_cell, store_history=False, silent=False):
264 def pxrun_cell(self, raw_cell, store_history=False, silent=False):
207 """drop-in replacement for InteractiveShell.run_cell.
265 """drop-in replacement for InteractiveShell.run_cell.
208
266
@@ -263,47 +321,16 b' class ParallelMagics(Magics):'
263 self.shell.showtraceback()
321 self.shell.showtraceback()
264 return True
322 return True
265 else:
323 else:
266 self._maybe_display_output(result)
324 with ipself.builtin_trap:
267 return False
325 result.display_outputs()
268
269 def pxrun_code(self, code_obj):
270 """drop-in replacement for InteractiveShell.run_code.
271
272 This executes code remotely, instead of in the local namespace.
273
274 See InteractiveShell.run_code for details.
275 """
276 ipself = self.shell
277 # check code object for the autopx magic
278 if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names \
279 and any( [ isinstance(c, basestring) and 'autopx' in c
280 for c in code_obj.co_consts ]):
281 self._disable_autopx()
282 return False
283 else:
284 try:
285 result = self.active_view.execute(code_obj, block=False)
286 except:
287 ipself.showtraceback()
288 return True
289 else:
290 if self.active_view.block:
291 try:
292 result.get()
293 except:
294 self.shell.showtraceback()
295 return True
296 else:
297 self._maybe_display_output(result)
298 return False
326 return False
299
327
300
328
301 __doc__ = __doc__.replace('@AUTOPX_DOC@',
329 __doc__ = __doc__.format(
302 " " + ParallelMagics.autopx.__doc__)
330 AUTOPX_DOC = ' '*8 + ParallelMagics.autopx.__doc__,
303 __doc__ = __doc__.replace('@PX_DOC@',
331 PX_DOC = ' '*8 + ParallelMagics.px.__doc__,
304 " " + ParallelMagics.px.__doc__)
332 RESULT_DOC = ' '*8 + ParallelMagics.result.__doc__
305 __doc__ = __doc__.replace('@RESULT_DOC@',
333 )
306 " " + ParallelMagics.result.__doc__)
307
334
308 _loaded = False
335 _loaded = False
309
336
@@ -21,7 +21,7 b' from datetime import datetime'
21
21
22 from zmq import MessageTracker
22 from zmq import MessageTracker
23
23
24 from IPython.core.display import clear_output
24 from IPython.core.display import clear_output, display
25 from IPython.external.decorator import decorator
25 from IPython.external.decorator import decorator
26 from IPython.parallel import error
26 from IPython.parallel import error
27
27
@@ -377,6 +377,140 b' class AsyncResult(object):'
377 sys.stdout.flush()
377 sys.stdout.flush()
378 print
378 print
379 print "done"
379 print "done"
380
381 def _republish_displaypub(self, content, eid):
382 """republish individual displaypub content dicts"""
383 try:
384 ip = get_ipython()
385 except NameError:
386 # displaypub is meaningless outside IPython
387 return
388 md = content['metadata'] or {}
389 md['engine'] = eid
390 ip.display_pub.publish(content['source'], content['data'], md)
391
392
393 def _display_single_result(self):
394
395 print self.stdout
396 print >> sys.stderr, self.stderr
397
398 try:
399 get_ipython()
400 except NameError:
401 # displaypub is meaningless outside IPython
402 return
403
404 for output in self.outputs:
405 self._republish_displaypub(output, self.engine_id)
406
407 if self.pyout is not None:
408 display(self.get())
409
410 @check_ready
411 def display_outputs(self, groupby="type"):
412 """republish the outputs of the computation
413
414 Parameters
415 ----------
416
417 groupby : str [default: type]
418 if 'type':
419 Group outputs by type (show all stdout, then all stderr, etc.):
420
421 [stdout:1] foo
422 [stdout:2] foo
423 [stderr:1] bar
424 [stderr:2] bar
425 if 'engine':
426 Display outputs for each engine before moving on to the next:
427
428 [stdout:1] foo
429 [stderr:1] bar
430 [stdout:2] foo
431 [stderr:2] bar
432
433 if 'order':
434 Like 'type', but further collate individual displaypub
435 outputs. This is meant for cases of each command producing
436 several plots, and you would like to see all of the first
437 plots together, then all of the second plots, and so on.
438 """
439 # flush iopub, just in case
440 self._client._flush_iopub(self._client._iopub_socket)
441 if self._single_result:
442 self._display_single_result()
443 return
444
445 stdouts = [s.rstrip() for s in self.stdout]
446 stderrs = [s.rstrip() for s in self.stderr]
447 pyouts = [p for p in self.pyout]
448 output_lists = self.outputs
449 results = self.get()
450
451 targets = self.engine_id
452
453 if groupby == "engine":
454 for eid,stdout,stderr,outputs,r,pyout in zip(
455 targets, stdouts, stderrs, output_lists, results, pyouts
456 ):
457 if stdout:
458 print '[stdout:%i]' % eid, stdout
459 if stderr:
460 print >> sys.stderr, '[stderr:%i]' % eid, stderr
461
462 try:
463 get_ipython()
464 except NameError:
465 # displaypub is meaningless outside IPython
466 return
467
468 for output in outputs:
469 self._republish_displaypub(output, eid)
470
471 if pyout is not None:
472 display(r)
473
474 elif groupby in ('type', 'order'):
475 # republish stdout:
476 if any(stdouts):
477 for eid,stdout in zip(targets, stdouts):
478 print '[stdout:%i]' % eid, stdout
479
480 # republish stderr:
481 if any(stderrs):
482 for eid,stderr in zip(targets, stderrs):
483 print >> sys.stderr, '[stderr:%i]' % eid, stderr
484
485 try:
486 get_ipython()
487 except NameError:
488 # displaypub is meaningless outside IPython
489 return
490
491 if groupby == 'order':
492 output_dict = dict((eid, outputs) for eid,outputs in zip(targets, output_lists))
493 N = max(len(outputs) for outputs in output_lists)
494 for i in range(N):
495 for eid in targets:
496 outputs = output_dict[eid]
497 if len(outputs) >= N:
498 self._republish_displaypub(outputs[i], eid)
499 else:
500 # republish displaypub output
501 for eid,outputs in zip(targets, output_lists):
502 for output in outputs:
503 self._republish_displaypub(output, eid)
504
505 # finally, add pyout:
506 for eid,r,pyout in zip(targets, results, pyouts):
507 if pyout is not None:
508 display(r)
509
510 else:
511 raise ValueError("groupby must be one of 'type', 'engine', 'collate', not %r" % groupby)
512
513
380
514
381
515
382 class AsyncMapResult(AsyncResult):
516 class AsyncMapResult(AsyncResult):
@@ -33,6 +33,7 b' import zmq'
33 from IPython.config.configurable import MultipleInstanceError
33 from IPython.config.configurable import MultipleInstanceError
34 from IPython.core.application import BaseIPythonApplication
34 from IPython.core.application import BaseIPythonApplication
35
35
36 from IPython.utils.coloransi import TermColors
36 from IPython.utils.jsonutil import rekey
37 from IPython.utils.jsonutil import rekey
37 from IPython.utils.localinterfaces import LOCAL_IPS
38 from IPython.utils.localinterfaces import LOCAL_IPS
38 from IPython.utils.path import get_ipython_dir
39 from IPython.utils.path import get_ipython_dir
@@ -90,13 +91,39 b' class ExecuteReply(object):'
90 return self.metadata[key]
91 return self.metadata[key]
91
92
92 def __repr__(self):
93 def __repr__(self):
93 pyout = self.metadata['pyout'] or {}
94 pyout = self.metadata['pyout'] or {'data':{}}
94 text_out = pyout.get('data', {}).get('text/plain', '')
95 text_out = pyout['data'].get('text/plain', '')
95 if len(text_out) > 32:
96 if len(text_out) > 32:
96 text_out = text_out[:29] + '...'
97 text_out = text_out[:29] + '...'
97
98
98 return "<ExecuteReply[%i]: %s>" % (self.execution_count, text_out)
99 return "<ExecuteReply[%i]: %s>" % (self.execution_count, text_out)
99
100
101 def _repr_pretty_(self, p, cycle):
102 pyout = self.metadata['pyout'] or {'data':{}}
103 text_out = pyout['data'].get('text/plain', '')
104
105 if not text_out:
106 return
107
108 try:
109 ip = get_ipython()
110 except NameError:
111 colors = "NoColor"
112 else:
113 colors = ip.colors
114
115 if colors == "NoColor":
116 out = normal = ""
117 else:
118 out = TermColors.Red
119 normal = TermColors.Normal
120
121 p.text(
122 u'[%i] ' % self.metadata['engine_id'] +
123 out + u'Out[%i]: ' % self.execution_count +
124 normal + text_out
125 )
126
100 def _repr_html_(self):
127 def _repr_html_(self):
101 pyout = self.metadata['pyout'] or {'data':{}}
128 pyout = self.metadata['pyout'] or {'data':{}}
102 return pyout['data'].get("text/html")
129 return pyout['data'].get("text/html")
@@ -15,6 +15,7 b' Authors:'
15 import sys
15 import sys
16 import tempfile
16 import tempfile
17 import time
17 import time
18 from StringIO import StringIO
18
19
19 from nose import SkipTest
20 from nose import SkipTest
20
21
@@ -59,6 +60,28 b' def raiser(eclass):'
59 """raise an exception"""
60 """raise an exception"""
60 raise eclass()
61 raise eclass()
61
62
63 def generate_output():
64 """function for testing output
65
66 publishes two outputs of each type, and returns
67 a rich displayable object.
68 """
69
70 import sys
71 from IPython.core.display import display, HTML, Math
72
73 print "stdout"
74 print >> sys.stderr, "stderr"
75
76 display(HTML("<b>HTML</b>"))
77
78 print "stdout2"
79 print >> sys.stderr, "stderr2"
80
81 display(Math(r"\alpha=\beta"))
82
83 return Math("42")
84
62 # test decorator for skipping tests when libraries are unavailable
85 # test decorator for skipping tests when libraries are unavailable
63 def skip_without(*names):
86 def skip_without(*names):
64 """skip a test if some names are not importable"""
87 """skip a test if some names are not importable"""
@@ -73,6 +96,41 b' def skip_without(*names):'
73 return f(*args, **kwargs)
96 return f(*args, **kwargs)
74 return skip_without_names
97 return skip_without_names
75
98
99 #-------------------------------------------------------------------------------
100 # Classes
101 #-------------------------------------------------------------------------------
102
103 class CapturedIO(object):
104 """Simple object for containing captured stdout/err StringIO objects"""
105
106 def __init__(self, stdout, stderr):
107 self.stdout_io = stdout
108 self.stderr_io = stderr
109
110 @property
111 def stdout(self):
112 return self.stdout_io.getvalue()
113
114 @property
115 def stderr(self):
116 return self.stderr_io.getvalue()
117
118
119 class capture_output(object):
120 """context manager for capturing stdout/err"""
121
122 def __enter__(self):
123 self.sys_stdout = sys.stdout
124 self.sys_stderr = sys.stderr
125 stdout = sys.stdout = StringIO()
126 stderr = sys.stderr = StringIO()
127 return CapturedIO(stdout, stderr)
128
129 def __exit__(self, exc_type, exc_value, traceback):
130 sys.stdout = self.sys_stdout
131 sys.stderr = self.sys_stderr
132
133
76 class ClusterTestCase(BaseZMQTestCase):
134 class ClusterTestCase(BaseZMQTestCase):
77
135
78 def add_engines(self, n=1, block=True):
136 def add_engines(self, n=1, block=True):
@@ -117,6 +175,17 b' class ClusterTestCase(BaseZMQTestCase):'
117 else:
175 else:
118 self.fail("should have raised a RemoteError")
176 self.fail("should have raised a RemoteError")
119
177
178 def _wait_for(self, f, timeout=10):
179 """wait for a condition"""
180 tic = time.time()
181 while time.time() <= tic + timeout:
182 if f():
183 return
184 time.sleep(0.1)
185 self.client.spin()
186 if not f():
187 print "Warning: Awaited condition never arrived"
188
120 def setUp(self):
189 def setUp(self):
121 BaseZMQTestCase.setUp(self)
190 BaseZMQTestCase.setUp(self)
122 self.client = self.connect_client()
191 self.client = self.connect_client()
@@ -366,118 +366,6 b' class TestView(ClusterTestCase, ParametricTestCase):'
366
366
367 self.assertEquals(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
367 self.assertEquals(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
368
368
369 # parallel magic tests
370
371 def test_magic_px_blocking(self):
372 ip = get_ipython()
373 v = self.client[-1]
374 v.activate()
375 v.block=True
376
377 ip.magic('px a=5')
378 self.assertEquals(v['a'], 5)
379 ip.magic('px a=10')
380 self.assertEquals(v['a'], 10)
381 sio = StringIO()
382 savestdout = sys.stdout
383 sys.stdout = sio
384 # just 'print a' worst ~99% of the time, but this ensures that
385 # the stdout message has arrived when the result is finished:
386 ip.magic('px import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)')
387 sys.stdout = savestdout
388 buf = sio.getvalue()
389 self.assertTrue('[stdout:' in buf, buf)
390 self.assertTrue(buf.rstrip().endswith('10'))
391 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
392
393 def test_magic_px_nonblocking(self):
394 ip = get_ipython()
395 v = self.client[-1]
396 v.activate()
397 v.block=False
398
399 ip.magic('px a=5')
400 self.assertEquals(v['a'], 5)
401 ip.magic('px a=10')
402 self.assertEquals(v['a'], 10)
403 sio = StringIO()
404 savestdout = sys.stdout
405 sys.stdout = sio
406 ip.magic('px print a')
407 sys.stdout = savestdout
408 buf = sio.getvalue()
409 self.assertFalse('[stdout:%i]'%v.targets in buf)
410 ip.magic('px 1/0')
411 ar = v.get_result(-1)
412 self.assertRaisesRemote(ZeroDivisionError, ar.get)
413
414 def test_magic_autopx_blocking(self):
415 ip = get_ipython()
416 v = self.client[-1]
417 v.activate()
418 v.block=True
419
420 sio = StringIO()
421 savestdout = sys.stdout
422 sys.stdout = sio
423 ip.magic('autopx')
424 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
425 ip.run_cell('b*=2')
426 ip.run_cell('print (b)')
427 ip.run_cell("b/c")
428 ip.magic('autopx')
429 sys.stdout = savestdout
430 output = sio.getvalue().strip()
431 self.assertTrue(output.startswith('%autopx enabled'))
432 self.assertTrue(output.endswith('%autopx disabled'))
433 self.assertTrue('RemoteError: ZeroDivisionError' in output)
434 ar = v.get_result(-1)
435 self.assertEquals(v['a'], 5)
436 self.assertEquals(v['b'], 20)
437 self.assertRaisesRemote(ZeroDivisionError, ar.get)
438
439 def test_magic_autopx_nonblocking(self):
440 ip = get_ipython()
441 v = self.client[-1]
442 v.activate()
443 v.block=False
444
445 sio = StringIO()
446 savestdout = sys.stdout
447 sys.stdout = sio
448 ip.magic('autopx')
449 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
450 ip.run_cell('print (b)')
451 ip.run_cell('import time; time.sleep(0.1)')
452 ip.run_cell("b/c")
453 ip.run_cell('b*=2')
454 ip.magic('autopx')
455 sys.stdout = savestdout
456 output = sio.getvalue().strip()
457 self.assertTrue(output.startswith('%autopx enabled'))
458 self.assertTrue(output.endswith('%autopx disabled'))
459 self.assertFalse('ZeroDivisionError' in output)
460 ar = v.get_result(-2)
461 self.assertRaisesRemote(ZeroDivisionError, ar.get)
462 # prevent TaskAborted on pulls, due to ZeroDivisionError
463 time.sleep(0.5)
464 self.assertEquals(v['a'], 5)
465 # b*=2 will not fire, due to abort
466 self.assertEquals(v['b'], 10)
467
468 def test_magic_result(self):
469 ip = get_ipython()
470 v = self.client[-1]
471 v.activate()
472 v['a'] = 111
473 ra = v['a']
474
475 ar = ip.magic('result')
476 self.assertEquals(ar.msg_ids, [v.history[-1]])
477 self.assertEquals(ar.get(), 111)
478 ar = ip.magic('result -2')
479 self.assertEquals(ar.msg_ids, [v.history[-2]])
480
481 def test_unicode_execute(self):
369 def test_unicode_execute(self):
482 """test executing unicode strings"""
370 """test executing unicode strings"""
483 v = self.client[-1]
371 v = self.client[-1]
@@ -575,16 +463,6 b' class TestView(ClusterTestCase, ParametricTestCase):'
575
463
576
464
577 # begin execute tests
465 # begin execute tests
578 def _wait_for(self, f, timeout=10):
579 tic = time.time()
580 while time.time() <= tic + timeout:
581 if f():
582 return
583 time.sleep(0.1)
584 self.client.spin()
585 if not f():
586 print "Warning: Awaited condition never arrived"
587
588
466
589 def test_execute_reply(self):
467 def test_execute_reply(self):
590 e0 = self.client[self.client.ids[0]]
468 e0 = self.client[self.client.ids[0]]
@@ -31,12 +31,15 b' class ZMQDisplayHook(object):'
31
31
32
32
33 def _encode_binary(format_dict):
33 def _encode_binary(format_dict):
34 encoded = format_dict.copy()
34 pngdata = format_dict.get('image/png')
35 pngdata = format_dict.get('image/png')
35 if pngdata is not None:
36 if isinstance(pngdata, bytes):
36 format_dict['image/png'] = encodestring(pngdata).decode('ascii')
37 encoded['image/png'] = encodestring(pngdata).decode('ascii')
37 jpegdata = format_dict.get('image/jpeg')
38 jpegdata = format_dict.get('image/jpeg')
38 if jpegdata is not None:
39 if isinstance(jpegdata, bytes):
39 format_dict['image/jpeg'] = encodestring(jpegdata).decode('ascii')
40 encoded['image/jpeg'] = encodestring(jpegdata).decode('ascii')
41
42 return encoded
40
43
41
44
42 class ZMQShellDisplayHook(DisplayHook):
45 class ZMQShellDisplayHook(DisplayHook):
@@ -61,8 +64,7 b' class ZMQShellDisplayHook(DisplayHook):'
61 self.msg['content']['execution_count'] = self.prompt_count
64 self.msg['content']['execution_count'] = self.prompt_count
62
65
63 def write_format_data(self, format_dict):
66 def write_format_data(self, format_dict):
64 _encode_binary(format_dict)
67 self.msg['content']['data'] = _encode_binary(format_dict)
65 self.msg['content']['data'] = format_dict
66
68
67 def finish_displayhook(self):
69 def finish_displayhook(self):
68 """Finish up all displayhook activities."""
70 """Finish up all displayhook activities."""
@@ -382,6 +382,8 b' class Kernel(Configurable):'
382 # runlines. We'll need to clean up this logic later.
382 # runlines. We'll need to clean up this logic later.
383 if shell._reply_content is not None:
383 if shell._reply_content is not None:
384 reply_content.update(shell._reply_content)
384 reply_content.update(shell._reply_content)
385 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
386 reply_content['engine_info'] = e_info
385 # reset after use
387 # reset after use
386 shell._reply_content = None
388 shell._reply_content = None
387
389
@@ -77,8 +77,7 b' class ZMQDisplayPublisher(DisplayPublisher):'
77 self._validate_data(source, data, metadata)
77 self._validate_data(source, data, metadata)
78 content = {}
78 content = {}
79 content['source'] = source
79 content['source'] = source
80 _encode_binary(data)
80 content['data'] = _encode_binary(data)
81 content['data'] = data
82 content['metadata'] = metadata
81 content['metadata'] = metadata
83 self.session.send(
82 self.session.send(
84 self.pub_socket, u'display_data', json_clean(content),
83 self.pub_socket, u'display_data', json_clean(content),
@@ -120,21 +120,19 b' using our :func:`psum` function:'
120
120
121 In [1]: from IPython.parallel import Client
121 In [1]: from IPython.parallel import Client
122
122
123 In [2]: %load_ext parallel_magic
124
125 In [3]: c = Client(profile='mpi')
123 In [3]: c = Client(profile='mpi')
126
124
127 In [4]: view = c[:]
125 In [4]: view = c[:]
128
126
129 In [5]: view.activate()
127 In [5]: view.activate() # enabe magics
130
128
131 # run the contents of the file on each engine:
129 # run the contents of the file on each engine:
132 In [6]: view.run('psum.py')
130 In [6]: view.run('psum.py')
133
131
134 In [6]: px a = np.random.rand(100)
132 In [6]: %px a = np.random.rand(100)
135 Parallel execution on engines: [0,1,2,3]
133 Parallel execution on engines: [0,1,2,3]
136
134
137 In [8]: px s = psum(a)
135 In [8]: %px s = psum(a)
138 Parallel execution on engines: [0,1,2,3]
136 Parallel execution on engines: [0,1,2,3]
139
137
140 In [9]: view['s']
138 In [9]: view['s']
@@ -389,11 +389,11 b' Parallel magic commands'
389 -----------------------
389 -----------------------
390
390
391 We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``)
391 We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``)
392 that make it more pleasant to execute Python commands on the engines
392 that make it a bit more pleasant to execute Python commands on the engines interactively.
393 interactively. These are simply shortcuts to :meth:`execute` and
393 These are simply shortcuts to :meth:`.DirectView.execute`
394 :meth:`get_result` of the :class:`DirectView`. The ``%px`` magic executes a single
394 and :meth:`.AsyncResult.display_outputs` methods repsectively.
395 Python command on the engines specified by the :attr:`targets` attribute of the
395 The ``%px`` magic executes a single Python command on the engines
396 :class:`DirectView` instance:
396 specified by the :attr:`targets` attribute of the :class:`DirectView` instance:
397
397
398 .. sourcecode:: ipython
398 .. sourcecode:: ipython
399
399
@@ -413,43 +413,127 b' Python command on the engines specified by the :attr:`targets` attribute of the'
413 In [27]: %px a = numpy.random.rand(2,2)
413 In [27]: %px a = numpy.random.rand(2,2)
414 Parallel execution on engines: [0, 1, 2, 3]
414 Parallel execution on engines: [0, 1, 2, 3]
415
415
416 In [28]: %px ev = numpy.linalg.eigvals(a)
416 In [28]: %px numpy.linalg.eigvals(a)
417 Parallel execution on engines: [0, 1, 2, 3]
417 Parallel execution on engines: [0, 1, 2, 3]
418 [0] Out[68]: array([ 0.77120707, -0.19448286])
419 [1] Out[68]: array([ 1.10815921, 0.05110369])
420 [2] Out[68]: array([ 0.74625527, -0.37475081])
421 [3] Out[68]: array([ 0.72931905, 0.07159743])
422
423 In [29]: %px print 'hi'
424 Parallel execution on engine(s): [0, 1, 2, 3]
425 [stdout:0] hi
426 [stdout:1] hi
427 [stdout:2] hi
428 [stdout:3] hi
429
430
431 Since engines are IPython as well, you can even run magics remotely:
432
433 .. sourcecode:: ipython
434
435 In [28]: %px %pylab inline
436 Parallel execution on engine(s): [0, 1, 2, 3]
437 [stdout:0]
438 Welcome to pylab, a matplotlib-based Python environment...
439 For more information, type 'help(pylab)'.
440 [stdout:1]
441 Welcome to pylab, a matplotlib-based Python environment...
442 For more information, type 'help(pylab)'.
443 [stdout:2]
444 Welcome to pylab, a matplotlib-based Python environment...
445 For more information, type 'help(pylab)'.
446 [stdout:3]
447 Welcome to pylab, a matplotlib-based Python environment...
448 For more information, type 'help(pylab)'.
449
450 And once in pylab mode with the inline backend,
451 you can make plots and they will be displayed in your frontend
452 if it suports the inline figures (e.g. notebook or qtconsole):
453
454 .. sourcecode:: ipython
455
456 In [40]: %px plot(rand(100))
457 Parallel execution on engine(s): [0, 1, 2, 3]
458 <plot0>
459 <plot1>
460 <plot2>
461 <plot3>
462 [0] Out[79]: [<matplotlib.lines.Line2D at 0x10a6286d0>]
463 [1] Out[79]: [<matplotlib.lines.Line2D at 0x10b9476d0>]
464 [2] Out[79]: [<matplotlib.lines.Line2D at 0x110652750>]
465 [3] Out[79]: [<matplotlib.lines.Line2D at 0x10c6566d0>]
418
466
419 In [28]: dv['ev']
420 Out[28]: [ array([ 1.09522024, -0.09645227]),
421 ....: array([ 1.21435496, -0.35546712]),
422 ....: array([ 0.72180653, 0.07133042]),
423 ....: array([ 1.46384341, 1.04353244e-04])
424 ....: ]
425
467
426 The ``%result`` magic gets the most recent result, or takes an argument
468 ``%%px`` Cell Magic
427 specifying the index of the result to be requested. It is simply a shortcut to the
469 *******************
428 :meth:`get_result` method:
470
471 `%%px` can also be used as a Cell Magic, which accepts ``--[no]block`` flags,
472 and a ``--group-outputs`` argument, which adjust how the outputs of multiple
473 engines are presented.
474
475 .. seealso::
476
477 :meth:`.AsyncResult.display_outputs` for the grouping options.
429
478
430 .. sourcecode:: ipython
479 .. sourcecode:: ipython
480
481 In [50]: %%px --block --group-outputs=engine
482 ....: import numpy as np
483 ....: A = np.random.random((2,2))
484 ....: ev = numpy.linalg.eigvals(A)
485 ....: print ev
486 ....: ev.max()
487 ....:
488 Parallel execution on engine(s): [0, 1, 2, 3]
489 [stdout:0] [ 0.60640442 0.95919621]
490 [0] Out[73]: 0.9591962130899806
491 [stdout:1] [ 0.38501813 1.29430871]
492 [1] Out[73]: 1.2943087091452372
493 [stdout:2] [-0.85925141 0.9387692 ]
494 [2] Out[73]: 0.93876920456230284
495 [stdout:3] [ 0.37998269 1.24218246]
496 [3] Out[73]: 1.2421824618493817
497
498 ``%result`` Magic
499 *****************
500
501 If you are using ``%px`` in non-blocking mode, you won't get output.
502 You can use ``%result`` to display the outputs of the latest command,
503 just as is done when ``%px`` is blocking:
504
505 .. sourcecode:: ipython
506
507 In [39]: dv.block = False
431
508
432 In [29]: dv.apply_async(lambda : ev)
509 In [40]: %px print 'hi'
510 Async parallel execution on engine(s): [0, 1, 2, 3]
433
511
434 In [30]: %result
512 In [41]: %result
435 Out[30]: [ [ 1.28167017 0.14197338],
513 [stdout:0] hi
436 ....: [-0.14093616 1.27877273],
514 [stdout:1] hi
437 ....: [-0.37023573 1.06779409],
515 [stdout:2] hi
438 ....: [ 0.83664764 -0.25602658] ]
516 [stdout:3] hi
517
518 ``%result`` simply calls :meth:`.AsyncResult.display_outputs` on the most recent request.
519 You can pass integers as indices if you want a result other than the latest,
520 e.g. ``%result -2``, or ``%result 0`` for the first.
521
522
523 ``%autopx``
524 ***********
439
525
440 The ``%autopx`` magic switches to a mode where everything you type is executed
526 The ``%autopx`` magic switches to a mode where everything you type is executed
441 on the engines given by the :attr:`targets` attribute:
527 on the engines until you do ``%autopx`` again.
442
528
443 .. sourcecode:: ipython
529 .. sourcecode:: ipython
444
530
445 In [30]: dv.block=False
531 In [30]: dv.block=True
446
532
447 In [31]: %autopx
533 In [31]: %autopx
448 Auto Parallel Enabled
534 %autopx enabled
449 Type %autopx to disable
450
535
451 In [32]: max_evals = []
536 In [32]: max_evals = []
452 <IPython.parallel.AsyncResult object at 0x17b8a70>
453
537
454 In [33]: for i in range(100):
538 In [33]: for i in range(100):
455 ....: a = numpy.random.rand(10,10)
539 ....: a = numpy.random.rand(10,10)
@@ -457,22 +541,15 b' on the engines given by the :attr:`targets` attribute:'
457 ....: evals = numpy.linalg.eigvals(a)
541 ....: evals = numpy.linalg.eigvals(a)
458 ....: max_evals.append(evals[0].real)
542 ....: max_evals.append(evals[0].real)
459 ....:
543 ....:
460 ....:
461 <IPython.parallel.AsyncResult object at 0x17af8f0>
462
463 In [34]: %autopx
464 Auto Parallel Disabled
465
544
466 In [35]: dv.block=True
545 In [34]: print "Average max eigenvalue is: %f" % (sum(max_evals)/len(max_evals))
467
546 [stdout:0] Average max eigenvalue is: 10.193101
468 In [36]: px ans= "Average max eigenvalue is: %f"%(sum(max_evals)/len(max_evals))
547 [stdout:1] Average max eigenvalue is: 10.064508
469 Parallel execution on engines: [0, 1, 2, 3]
548 [stdout:2] Average max eigenvalue is: 10.055724
549 [stdout:3] Average max eigenvalue is: 10.086876
470
550
471 In [37]: dv['ans']
551 In [35]: %autopx
472 Out[37]: [ 'Average max eigenvalue is: 10.1387247332',
552 Auto Parallel Disabled
473 ....: 'Average max eigenvalue is: 10.2076902286',
474 ....: 'Average max eigenvalue is: 10.1891484655',
475 ....: 'Average max eigenvalue is: 10.1158837784',]
476
553
477
554
478 Moving Python objects around
555 Moving Python objects around
General Comments 0
You need to be logged in to leave comments. Login now