为什么 Python 共享内存需要一个副本?
Why Python shared memory requires a copy?
我试图通过修改共享的 numpy 数组来构建一个新的 Python SharedMemory class 的简单示例。我在网上看到了几个例子:
Shared memory in multiprocessing
Is shared readonly data copied to different processes for multiprocessing?
然而,出于某种原因,他们都更改了 __main__
块内的共享数组,然后只打印它。但是,我想从函数中 return 一个共享数组并在以后重用它。这是我的尝试:
from multiprocessing import shared_memory
import numpy as np
def create_shared_array():
# instantiate array
np_array = np.ones((5, 2, 2))
# instantiate shared array
shm = shared_memory.SharedMemory(size=np_array.nbytes, create=True)
# copy data from original array into shared array
array_shared = np.ndarray(np_array.shape, dtype=np_array.dtype, buffer=shm.buf)
array_shared[:] = np_array[:]
return shm
def change_and_return(name):
existing_shm = shared_memory.SharedMemory(name=name, create=False)
array_shared = np.ndarray((5, 2, 2), dtype=np.float64, buffer=existing_shm.buf)
# change shared array
array_shared[0] = 888
return array_shared
shm = create_shared_array()
result = change_and_return(shm.name)
print(result)
出于某种原因,这段代码 returns "The instruction at <memory address> referenced memory at <another address>. The memory could not be read."
在我的 Windows 机器上。
但是,如果我只是替换这个
return array_shared
有了这个
return array_shared.copy()
然后就可以正常工作了。
我的想法:
因为 change_and_return
没有 return existing_shm
然后它被垃圾收集并且 array_shared
也被销毁。但是,我确保不会杀死 shm
,所以引用应该仍然存在?
问题:为什么需要额外的副本以及避免额外副本的正确方法是什么?
更新:让我在这里说清楚——我想更改共享内存中的数组值,但在那之后我想以非共享方式使用它。就像一个普通的 numpy 数组。所以问题基本上是是否可以在不复制的情况下将共享数组变回非共享数组?
副本错误。它使一个数组由 非共享内存 支持,完全违背了你正在做的事情。
你这么说
However, I do make sure not to kill shm
但事实并非如此。你没有做任何事来让 shm
活着。它死了,它的 __del__
method 调用 close
,内存不再可访问。
您需要保留对 shm
的引用以确保内存仍可访问。此外,为了进行适当的清理,每个进程在不再需要使用共享内存后应调用 shm.close()
,并且在所有进程调用 close
后,单个进程应调用 shm.unlink()
。否则,即使在您的程序终止后 ,您仍有泄漏内存的风险。 (在 Unix 上,Python 生成一个 server process 来尝试防止这种情况发生,但它并不完全可靠,即使有效,它也会延迟执行清理。)
我试图通过修改共享的 numpy 数组来构建一个新的 Python SharedMemory class 的简单示例。我在网上看到了几个例子:
Shared memory in multiprocessing
Is shared readonly data copied to different processes for multiprocessing?
然而,出于某种原因,他们都更改了 __main__
块内的共享数组,然后只打印它。但是,我想从函数中 return 一个共享数组并在以后重用它。这是我的尝试:
from multiprocessing import shared_memory
import numpy as np
def create_shared_array():
# instantiate array
np_array = np.ones((5, 2, 2))
# instantiate shared array
shm = shared_memory.SharedMemory(size=np_array.nbytes, create=True)
# copy data from original array into shared array
array_shared = np.ndarray(np_array.shape, dtype=np_array.dtype, buffer=shm.buf)
array_shared[:] = np_array[:]
return shm
def change_and_return(name):
existing_shm = shared_memory.SharedMemory(name=name, create=False)
array_shared = np.ndarray((5, 2, 2), dtype=np.float64, buffer=existing_shm.buf)
# change shared array
array_shared[0] = 888
return array_shared
shm = create_shared_array()
result = change_and_return(shm.name)
print(result)
出于某种原因,这段代码 returns "The instruction at <memory address> referenced memory at <another address>. The memory could not be read."
在我的 Windows 机器上。
但是,如果我只是替换这个
return array_shared
有了这个
return array_shared.copy()
然后就可以正常工作了。
我的想法:
因为 change_and_return
没有 return existing_shm
然后它被垃圾收集并且 array_shared
也被销毁。但是,我确保不会杀死 shm
,所以引用应该仍然存在?
问题:为什么需要额外的副本以及避免额外副本的正确方法是什么?
更新:让我在这里说清楚——我想更改共享内存中的数组值,但在那之后我想以非共享方式使用它。就像一个普通的 numpy 数组。所以问题基本上是是否可以在不复制的情况下将共享数组变回非共享数组?
副本错误。它使一个数组由 非共享内存 支持,完全违背了你正在做的事情。
你这么说
However, I do make sure not to kill
shm
但事实并非如此。你没有做任何事来让 shm
活着。它死了,它的 __del__
method 调用 close
,内存不再可访问。
您需要保留对 shm
的引用以确保内存仍可访问。此外,为了进行适当的清理,每个进程在不再需要使用共享内存后应调用 shm.close()
,并且在所有进程调用 close
后,单个进程应调用 shm.unlink()
。否则,即使在您的程序终止后 ,您仍有泄漏内存的风险。 (在 Unix 上,Python 生成一个 server process 来尝试防止这种情况发生,但它并不完全可靠,即使有效,它也会延迟执行清理。)