1

我试图了解 IPython 并行的非复制发送/接收 numpy 数组会发生什么。我知道消息的非复制接收是只读的,但这让我期望我收到的 numpy 数组就像一个视图,指向原始数组(至少在共享内存机器上)。然后,我希望如果在其中一个计算节点上修改了 numpy 数组,我在笔记本中对该数组的视图将会更新,但是,情况似乎并非如此。为了演示让我感到困惑的事情,代码

from IPython.parallel import Client
dv = Client()[:]

with dv.sync_imports():
    import numpy 

dv.execute('a = numpy.zeros(2)')
print dv['a']
mya = dv['a'][1] # my copy of the array in the notebook
# mya[0] = -1 # can't assign to mya because it is read-only
dv.execute('a[1] = 1') # update the arrays on the compute nodes
print mya # value of mya is not updated
print dv['a'] # even though the arrays are updated on the compute nodes

有输出

importing numpy on engine(s)
[array([ 0.,  0.]), array([ 0.,  0.]), array([ 0.,  0.]), array([ 0.,  0.])]
[ 0.  0.]
[array([ 0.,  1.]), array([ 0.,  1.]), array([ 0.,  1.]), array([ 0.,  1.])]

我认为进行非复制发送的目的是通过让数组的每个视图都指向同一块内存来节省内存,但这里似乎并非如此。幕后发生了什么,我如何误解非复制发送的使用?

我上面的主要问题的上下文是共享内存环境(我的笔记本电脑),但我可能遇到的一个相关问题是 numpy 数组的非复制发送如何工作以及它们在分布式内存情况下的用途是什么,其中计算节点是不同的物理机器,您必须(我假设)通过网络发送 numpy 数组(有效地在接收机器上制作副本),因此查看原始内存位置是没有意义的。

4

1 回答 1

1

IPython.parallel(或底层 zeromq)上下文中的非复制发送并不意味着与目标共享内存。IPython.parallel 不是基于共享内存系统,而是基于显式消息传递。

相反,这意味着网络接口直接从您提供的数组中检索其数据,而不是将数据复制到网络堆栈中自己的缓冲区中。到目标进程或线程的传输仍将始终是一个副本,即使它在同一台机器上。

所以数据的接收方可以修改数据而不改变发送方的数据。但是发送者必须注意在将数据复制到目的地之前不要修改它提供给网络接口的缓冲区。使用 pyzmq 这可以通过使用track关键字参数来完成,该参数为您提供一个对象,您可以轮询该对象以完成传输,并且缓冲区再次可用于修改。

非复制发送是一种危险的优化,因为您必须非常小心哪些缓冲区可用于写入,哪些不可用。只有在明确指出网络堆栈的附加副本是性能问题时,才应该使用它们。

于 2015-02-19T22:17:41.490 回答