环绕我的头 IPython 平行

Wrapping My Head Around IPython Parallel

我正在努力思考在我的 python 代码中应用并行计算的基本概念。我已经阅读了很多关于 IPython parallel 的教程;但是,我似乎并不完全理解如何在一些基本 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')

我的问题:

  1. 有没有办法在所有命名空间中将 numpy 作为 np 包含一次而不是在这里包含两次? (一次在第一个上层导入中,然后在 execute() 中第二次。

  2. 与第一个问题相同,但针对 MyClass。有没有更优雅的方法将 MyClass 包含在所有命名空间中,而不是显式地将 class 类型作为变量推送?

  3. 您将如何以最优雅的方式编写上述代码pythonic/ipythonic?

我发现将 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]...。 类 和并行进程不能很好地协同工作,因为 class 实例的主要思想是具有状态(以成员变量的形式),而有状态函数很难并行化。因此,作为并行化的一般方法,请尝试使用 dview.map(),因为它负责将数组拆分为块并将其分发给客户端。它还强制传递的函数没有本地状态。如果你需要在每个进程中都有一个本地状态,使用问题2的方法。