In [1]:
%pylab inline
import numpy as np
import matplotlib.pyplot as plt
In [2]:
from IPython.core.display import Image
Image("parallel_architecture400.png")
Out[2]:
Three Core Parts
Client
object connects to the clusterView
DirectView
class for explicitly running code on a particular engine(s)LoadBalancedView
class for running your code on the 'best' engine(s)
In [3]:
from multiprocessing import cpu_count
print cpu_count()
At the command line type
ipcluster start -n 4
In [4]:
from IPython import parallel
rc = parallel.Client()
rc.block = True
In [5]:
def power(a, b):
return a**b
direct view
of kernel 0
In [6]:
dv = rc[0]
dv
Out[6]:
In [7]:
dv.apply(power, 2, 10)
Out[7]:
Recall that slice notation allows you leave out start and stop steps
In [8]:
X = [1, 2, 3, 4]
X
Out[8]:
In [9]:
X[:]
Out[9]:
Use this to send code to all the engines
In [10]:
rc[:].apply_sync(power, 2, 10)
Out[10]:
Python's built-in map function allows you to call a sequence a function over a sequences of arguments
In [11]:
map(power, [2]*10, range(10))
Out[11]:
In parallel, you use view.map
In [12]:
view = rc.load_balanced_view()
view.map(power, [2]*10, range(10))
Out[12]:
In [13]:
from IPython import parallel
rc = parallel.Client()
map
and apply
in parallel
In [14]:
rc.block = True
In [15]:
dview = rc[:]
In [16]:
dview.block = False
dview["a"] = 5 # shorthand for push
dview["b"] = 7
dview.apply_sync(lambda x: a + b + x, 27)
Out[16]:
apply_async
push
ing python objects to the engineskey
or by using get
and update
like built-in dictspush
push
takes a dictionary
In [17]:
dview.push(dict(msg="Hi, there"), block=True)
Out[17]:
In [18]:
dview.block = True
In [19]:
dview.execute("x = msg")
Out[19]:
Or using the interactive %px
magic, short for "parallel execute"
In [20]:
%px y = msg + ' you'
In [21]:
print dview["x"] # shorthand for pull
print dview["y"]
In [22]:
rc[::2].execute("c = a + b")
rc[1::2].execute("c = a - b")
Out[22]:
In [23]:
dview.pull("c")
Out[23]:
AsyncResult
object back immediately
In [24]:
def wait(t):
import time
tic = time.time()
time.sleep(t)
return time.time() - tic
In [25]:
ar = dview.apply_async(wait, 2)
In [26]:
type(ar)
Out[26]:
In [27]:
ar.get()
Out[27]:
ready
method
In [28]:
ar = dview.apply_async(wait, 15)
print ar.ready()
In [29]:
ar.get(5)
wait
methodwait
can take an iterable of AsyncResults
In [30]:
result_list = [dview.apply_async(wait, 1) for i in range(8)]
In [31]:
dview.wait(result_list)
Out[31]:
In [32]:
result_list[0].get()
Out[32]:
Every IPython engine can be turned into a kernel in one command:
In [33]:
%%px
from IPython.parallel import bind_kernel
bind_kernel()
Let's send the engine IDs to all of them
In [34]:
dview.scatter('eid', rc.ids, flatten=True)
And open a console directly on one of them:
In [35]:
rc[0].execute("%qtconsole")
Out[35]:
scatter
to partition an iterable across enginesgather
pulls the results back
In [36]:
dview.scatter('x', range(64))
%px y = [i**10 for i in x]
y = dview.gather('y')
print y[:10]
%
indicates that we are using an IPython 'magic' function
In [37]:
rc = parallel.Client()
lview = rc.load_balanced_view()
In [38]:
lview.block = True
parallel_result = lview.map(lambda x:x**10, range(32))
print parallel_result[:10]