用地图写入切片引用?
Write into slice references with map?
我正在尝试写入本应通过引用传递给函数的 Python 切片。
def mpfunc(r):
r[:]=1
R=np.zeros((2,4))
mpfunc(R[0])
mpfunc(R[1])
print(R)
此代码按预期工作。 R
现在包含 1
。
当我使用map()
时,然而
def mpfunc(r):
r[:]=1
R=np.zeros((2,4))
map(mpfunc,R)
R
似乎 R
的切片不再通过引用传递,我从文档中不清楚这一点。 R
现在仍然是 0
。
最终,目标是使用 multiprocessin.Pool.map()
,不幸的是,由于同样的原因,它似乎失败了:
from multiprocessing import Pool
def mpfunc(r):
r[:]=1
R=np.zeros((2,4))
with Pool(2) as p:
p.map(mpfunc,R)
print(R)
为什么会这样?我该如何解决?
map
(in Python 3) 是惰性的,你需要消耗它来触发函数,考虑下面的简单例子:
def update_dict(dct):
dct.update({"x":1})
data = [{"x":0},{"x":0},{"x":0}]
mp = map(update_dict, data)
print(data)
lst = list(map(update_dict, data))
print(data)
输出
[{'x': 0}, {'x': 0}, {'x': 0}]
[{'x': 1}, {'x': 1}, {'x': 1}]
请记住,如果可能的话,您应该避免调用 map
来产生副作用,以免混淆处理这段代码的其他人。
由于您只是调用一个映射函数,它只是为您创建了一个生成器对象,而实际上它并没有完成调用。生成器是一种 Python 延迟或延迟执行的方式。
所以这是您可以做到的方法之一。
...: def mpfunc(r):
...: r[:]=1
...:
...: R=np.zeros((2,4))
...:
...: # mpfunc(R[0])
...: # mpfunc(R[1])
...: list(map(mpfunc, R))
...:
...: print(R)
只需通过创建列表或任何适合您的方法来使用地图功能。理想情况下,一个 next()
函数用于一个一个地使用它。
[[1. 1. 1. 1.]
[1. 1. 1. 1.]]
同样适用于您的多进程代码段。
所以在非多重处理的情况下你必须迭代iterable由map
函数返回以确保指定的函数已应用于所有传递的 iterables。但是 Pool.map
.
却不是这样
但是你遇到的是一个更大的问题。您现在将数组传递给位于不同地址 space 中的进程,并且无法通过引用完成此操作,除非基本 numpy
数组存储在共享内存中。
在下面的代码中,每个进程的全局变量R
将使用numpy
数组的共享内存实现进行初始化。现在 map
函数将与需要更新的数组索引一起使用:
import multiprocessing as mp
import numpy as np
import ctypes
def to_numpy_array(shared_array, shape):
'''Create a numpy array backed by a shared memory Array.'''
arr = np.ctypeslib.as_array(shared_array)
return arr.reshape(shape)
def to_shared_array(arr, ctype):
shared_array = mp.Array(ctype, arr.size, lock=False)
temp = np.frombuffer(shared_array, dtype=arr.dtype)
temp[:] = arr.flatten(order='C')
return shared_array
def init_worker(shared_array, shape):
global R
R = to_numpy_array(shared_array, shape)
def mpfunc(idx):
R[idx, :] = 1
if __name__ == '__main__':
R = np.zeros((2,4))
shape = R.shape
shared_array = to_shared_array(R, ctypes.c_int64)
# you have to now use the shared array as the base
R = to_numpy_array(shared_array, shape)
with mp.Pool(2, initializer=init_worker, initargs=(shared_array, shape)) as p:
p.map(mpfunc, range(shape[0]))
print(R)
打印:
[[1 1 1 1]
[1 1 1 1]]
我正在尝试写入本应通过引用传递给函数的 Python 切片。
def mpfunc(r):
r[:]=1
R=np.zeros((2,4))
mpfunc(R[0])
mpfunc(R[1])
print(R)
此代码按预期工作。 R
现在包含 1
。
当我使用map()
时,然而
def mpfunc(r):
r[:]=1
R=np.zeros((2,4))
map(mpfunc,R)
R
似乎 R
的切片不再通过引用传递,我从文档中不清楚这一点。 R
现在仍然是 0
。
最终,目标是使用 multiprocessin.Pool.map()
,不幸的是,由于同样的原因,它似乎失败了:
from multiprocessing import Pool
def mpfunc(r):
r[:]=1
R=np.zeros((2,4))
with Pool(2) as p:
p.map(mpfunc,R)
print(R)
为什么会这样?我该如何解决?
map
(in Python 3) 是惰性的,你需要消耗它来触发函数,考虑下面的简单例子:
def update_dict(dct):
dct.update({"x":1})
data = [{"x":0},{"x":0},{"x":0}]
mp = map(update_dict, data)
print(data)
lst = list(map(update_dict, data))
print(data)
输出
[{'x': 0}, {'x': 0}, {'x': 0}]
[{'x': 1}, {'x': 1}, {'x': 1}]
请记住,如果可能的话,您应该避免调用 map
来产生副作用,以免混淆处理这段代码的其他人。
由于您只是调用一个映射函数,它只是为您创建了一个生成器对象,而实际上它并没有完成调用。生成器是一种 Python 延迟或延迟执行的方式。 所以这是您可以做到的方法之一。
...: def mpfunc(r):
...: r[:]=1
...:
...: R=np.zeros((2,4))
...:
...: # mpfunc(R[0])
...: # mpfunc(R[1])
...: list(map(mpfunc, R))
...:
...: print(R)
只需通过创建列表或任何适合您的方法来使用地图功能。理想情况下,一个 next()
函数用于一个一个地使用它。
[[1. 1. 1. 1.]
[1. 1. 1. 1.]]
同样适用于您的多进程代码段。
所以在非多重处理的情况下你必须迭代iterable由map
函数返回以确保指定的函数已应用于所有传递的 iterables。但是 Pool.map
.
但是你遇到的是一个更大的问题。您现在将数组传递给位于不同地址 space 中的进程,并且无法通过引用完成此操作,除非基本 numpy
数组存储在共享内存中。
在下面的代码中,每个进程的全局变量R
将使用numpy
数组的共享内存实现进行初始化。现在 map
函数将与需要更新的数组索引一起使用:
import multiprocessing as mp
import numpy as np
import ctypes
def to_numpy_array(shared_array, shape):
'''Create a numpy array backed by a shared memory Array.'''
arr = np.ctypeslib.as_array(shared_array)
return arr.reshape(shape)
def to_shared_array(arr, ctype):
shared_array = mp.Array(ctype, arr.size, lock=False)
temp = np.frombuffer(shared_array, dtype=arr.dtype)
temp[:] = arr.flatten(order='C')
return shared_array
def init_worker(shared_array, shape):
global R
R = to_numpy_array(shared_array, shape)
def mpfunc(idx):
R[idx, :] = 1
if __name__ == '__main__':
R = np.zeros((2,4))
shape = R.shape
shared_array = to_shared_array(R, ctypes.c_int64)
# you have to now use the shared array as the base
R = to_numpy_array(shared_array, shape)
with mp.Pool(2, initializer=init_worker, initargs=(shared_array, shape)) as p:
p.map(mpfunc, range(shape[0]))
print(R)
打印:
[[1 1 1 1]
[1 1 1 1]]