简体   繁体   English

多处理多个大 numpy arrays 作为共享 memory

[英]Multiprocessing multiple big numpy arrays as shared memory

I have multiple big numpy arrays:我有多个大 numpy arrays:

x1=np.zeros((4000,4000))
x2=np.zeros((4000,4000))
x3=np.zeros((4000,4000))
.
.
.
xn=np.zeros((4000,4000))

and I want to execute a function with these arrays in parallel.我想用这些 arrays 并行执行 function 。 because every Array is independent of the others, I thought I could use shared_memory so that a subprocess does not pickle the data.因为每个数组都独立于其他数组,我想我可以使用 shared_memory 以便子进程不会腌制数据。

Is it possible to create a big "shared variable" which contain the 3 big numpy arrays?是否可以创建一个包含 3 个大 numpy arrays 的大“共享变量”?

Inside the subprocess I would like to write directly into these arrays (without pickle them).在子流程内部,我想直接写入这些 arrays (不腌制它们)。

I think a would pass the subprocesses an idx (0,1,2...n) argument to reference to the x1,x2,x3...xn arrays?我认为 a 会将子进程传递一个 idx (0,1,2...n) 参数以引用 x1,x2,x3...xn arrays?

Is this possible?这可能吗? I think one array is not the problem, but the multiple arrays multiprocessing is a bit confusing to me.我认为一个数组不是问题,但是多个 arrays 多处理让我有点困惑。

Thank you.谢谢你。

This is how you could do it using an array of shared memory.这就是使用共享 memory 数组的方法。

import numpy as np
import ctypes
from multiprocessing.sharedctypes import RawArray
from multiprocessing.pool import Pool

def main():
    n = ...  # Number of arrays
    # Make arrays
    x1 = np.zeros((4000, 4000), dtype=np.float64)
    x2 = np.zeros((4000, 4000), dtype=np.float64)
    # ...
    xn = np.zeros((4000, 4000), dtype=np.float64)
    # Make big array of shared memory (ctype must match array type)
    array_mem = RawArray(ctypes.c_double, n * 4000 * 4000)
    arr = np.frombuffer(array_mem, dtype=np.float64).reshape(n, 4000, 4000)
    arr[0] = x1
    arr[1] = x2
    # ...
    arr[n - 1] = xn
    # Process array in a pool of processes
    with Pool(initializer=init_process, initargs=(array_mem, arr.shape)) as p:
        p.map(process_array, range(n))
    # The array has been processed
    # ...
    print(*arr[:, :2, :3], sep='\n')
    # [[0. 0. 0.]
    #  [0. 0. 0.]]
    # [[100. 100. 100.]
    #  [100. 100. 100.]]
    # [[200. 200. 200.]
    #  [200. 200. 200.]]
    # ...

# Global values for subprocesses
process_array_mem = None
process_array_shape = None

# Process initializer saves memory pointer and array shape
def init_process(array_mem, array_shape):
    global process_array_mem, process_array_shape
    process_array_mem = array_mem
    process_array_shape = array_shape

def process_array(array_idx):
    # Create array from shared memory
    arr = np.frombuffer(process_array_mem, dtype=np.float64).reshape(process_array_shape)
    # Pick array for this process
    process_array = arr[array_idx]
    # Do processing
    process_array += 100 * array_idx

if __name__ == '__main__':
    main()

In the code above I put n =... to set the number of arrays to whatever value it has in your case, but if you change it to n = 3 and save the snippet as a file you can run it and see the result.在上面的代码中,我输入n =...将 arrays 的数量设置为在您的情况下具有的任何值,但是如果将其更改为n = 3并将代码段另存为文件,则可以运行它并查看结果. The initializer and global values part may be a bit confusing, but the thing is array_mem must be inherited by the subprocesses, which means I cannot pass it as another parameter with map , and I think this is the simplest way to use it.初始化器和全局值部分可能有点混乱,但问题是array_mem必须由子进程继承,这意味着我不能将它作为另一个参数传递给map ,我认为这是使用它的最简单方法。

You can use multiprocessing.Pool to process each array concurrently by applying a custom processing function to each of the individual array separately.您可以使用multiprocessing.Pool通过将自定义处理 function 分别应用于每个单独的数组来同时处理每个数组。 This can be achieved by map function of pool object.这可以通过池 object 的map function 来实现。

The map(func, iterable) : map(func, iterable)

Apply func to each element in iterable , collecting the results in a list that is returned.func应用于iterable中的每个元素,将结果收集到返回的列表中。

Consider the example code,考虑示例代码,

from multiprocessing import Pool

def process_array(arr):
    # ---> TODO: Process array
    arr += 1 # ---> e.g. add the scalar to entire array

    return arr # return processed array

if __name__ == "__main__":
    x1=np.zeros((4000,4000))
    x2=np.zeros((4000,4000))
    x3=np.zeros((4000,4000))

    with Pool() as pool:
        result = pool.map(process_array, [x1, x2, x3]) #--> all the three arrays will be processed parallely.

    print(result[0])
    print(result[1])
    print(result[2])

Sample Output:样品 Output:

[[1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 ...
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]]

[[1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 ...
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]]

[[1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 ...
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]
 [1. 1. 1. ... 1. 1. 1.]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM