我试图围绕在我的python代码中应用并行计算的基本概念。我已经阅读了很多关于IPython并行的教程;但是,我似乎并不完全理解如何在一些基本的python代码中优雅地应用它。例如,演示代码如下所示:my_script.py:
# imports
import numpy as np
from IPython.parallel import Client
# class definition
class MyClass():
def do_something(self, x, y):
return np.sum(x, y)
# some variables
x = [1, 2, 3, 4, 5, 6, 7, 8 ,9, 10]
y = [1, 2, 3, 4, 5, 6, 7, 8 ,9, 10]
# create client and direct view to all engines available
client = Client()
dview = client[:]
dview.block = True
# here is what i'm currently doing to achieve parallelism
dview.execute('import numpy as np')
dview['MyClass'] = MyClass
dview.scatter('x', x)
dview.scatter('y', y)
dview.execute('my = MyClass()')
dview.execute('z = my.do_something(x, y)')
z = dview.gather('z')
我的问题:
有没有办法在所有命名空间中将numpy包含为np一次而不是两次? (一次在第一个上导入,然后在执行()中第二个。
与第一个问题相同,但对于MyClass。有没有更优雅的方法在所有命名空间中包含MyClass,而不是明确地将类类型作为变量推送?
您如何以最优雅的pythonic / ipythonic方式编写上述代码?
答案 0 :(得分:2)
我认为将IPython视为在流程之间移动数据是有帮助的,但通常不是代码。值得注意的例外是函数(使用map()
和apply()
)。
问题1 :我认为只能导入一次numpy,因为您的主进程和客户端进程不相同。对于更易读的代码,您可以执行以下操作:
from IPython.parallel import Client
client = Client() # create client and direct view to all engines available
dview = client[:]
dview.block = True
with dview.sync_imports(): # import on all client processes
import numpy # `import numpy as np` does not work
def f(x , y):
""" return x**2 + y """
return numpy.power(x, 2) + y
x = np.arange(5)
y = 1000 * np.arange(5)
zz = dview.map(f, x, y) # execute f() in parallel on different clients
print(zz) # gives: [0, 1001, 2004, 3009, 4016]
查看IPython manual为什么import numpy as np
无效。
问题2 :在我看来,我认为最干净的方法是将MyClass
放在一个单独的文件中,然后像上面的numpy
一样导入它。原因是并行处理(MyClass
)和管理(分发和收集数据)应该是分开的。可以说这也是一个品味问题。
问题3 :您的方法do_something()
不起作用,因为np.sum()
总结了单个数组的元素。所以我假设您要并行计算x[0]+y[0]
,x[1]+y[1]
,...
。类和并行进程不能很好地结合在一起,因为类的实例的主要思想是具有状态(以成员变量的形式)并且有状态函数很难并行化。因此,作为并行化的一般方法,请尝试使用dview.map()
,因为它负责将数组拆分为块并将其分发给客户端。它还强制传递的函数不具有本地状态。如果您需要在每个流程中都有一个本地状态,请使用问题2的方法。