我试图了解IPython parallel的非复制发送/接收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阵列(有效地在接收机器上复制),因此查看原始内存位置是没有意义的。
答案 0 :(得分:1)
IPython.parallel(或底层的zeromq)上下文中的非复制发送并不意味着内存与目标共享。 IPython.parallel不是基于共享内存系统,而是基于显式消息传递。
它意味着网络接口直接从您提供的阵列中检索其数据,而不是将数据副本复制到网络堆栈中自己的缓冲区中。 转移到目标进程或线程仍将始终是一个副本,即使它位于同一台计算机上。
因此数据接收方可以修改数据而无需更改发送方的数据。
但是,在将数据复制到目标之前,发送方必须注意不要修改它给网络接口的缓冲区。使用pyzmq,这可以通过track
关键字参数来完成,该参数为您提供了一个对象,您可以轮询该传输以完成传输,并且缓冲区可以再次进行修改。
非复制发送是一种危险的优化,因为您必须非常小心哪些缓冲区可用于写入,哪些缓冲区不可用。只有在将附加副本明确地指向网络堆栈才会出现性能问题时,才应使用它们。