当通过管道传递大型数组时,Python多处理陷入困境

当通过管道传递大型数组时,Python多处理陷入困境,python,multiprocessing,pipe,Python,Multiprocessing,Pipe,我在python中使用多处理,并尝试通过管道将一个大的numpy数组传递给子进程。它适用于小数组,但对于较大的数组挂起而不返回错误 我相信管道堵塞了,已经读了一些关于它的文章,但无法找到解决问题的方法 def f2(conn, x): conn.start() data = conn.recv() conn.join() print(data) do_something(x) conn.close() if __name__ == '__ma

我在python中使用多处理,并尝试通过管道将一个大的numpy数组传递给子进程。它适用于小数组,但对于较大的数组挂起而不返回错误

我相信管道堵塞了,已经读了一些关于它的文章,但无法找到解决问题的方法

def f2(conn, x):
    conn.start()
    data = conn.recv()
    conn.join()

    print(data)
    do_something(x)

    conn.close()

if __name__ == '__main__':
    data_input = read_data()    # large numpy array
    parent_conn, child_conn = Pipe()

    p = multiprocessing.Pool(processes=8)      
    func = partial(f2, child_conn)

    parent_conn.send(data_input)
    parent_conn.close()

    result = p.map(func, processes)

    p.close()
    p.join()

忽略此代码中的所有其他问题(您没有要传递到
map
x
,您没有使用
x
f2
接收,混合
池。map
管道
通常是错误的做法),您的最终问题是在工作进程可以读取之前执行阻塞
send
调用

假设您确实希望将
映射
管道
混合使用,解决方案是在开始
发送
之前异步启动
映射
,因此在父级尝试写入时,另一侧有一些东西可以从
管道
读取:

if __name__ == '__main__':
    data_input = read_data()    # large numpy array
    parent_conn, child_conn = Pipe()

    # Use with to avoid needing to explicitly close/join
    with multiprocessing.Pool(processes=8) as p:
        func = partial(f2, child_conn)

        # Launch async map to ensure workers are running
        future = p.map_async(func, x)

        # Can perform blocking send as workers will consume as you send
        parent_conn.send(data_input)
        parent_conn.close()

        # Now you can wait on the map to complete
        result = future.get()
如前所述,由于
x
的问题,此代码将不会运行,
Pipe
文档明确警告不应同时从
管道读取两个不同的进程

如果您想在单个辅助进程中批量处理数据,只需使用
process
Pipe
,类似于:

def f2(conn):
    data = conn.recv()
    conn.close()
    print(data)

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()

    proc = multiprocessing.Process(target=f2, args=(child_conn,))
    proc.start()

    data_input = read_data()    # large numpy array
    parent_conn.send(data_input)
    parent_conn.close()

    proc.join()
如果您想在多个工作区中分别处理每个元素,只需使用
Pool
map

def f2(x):
    print(x)

if __name__ == '__main__':
    data_input = read_data()    # large numpy array
    with multiprocessing.Pool(processes=8) as p:   
        result = p.map(f2, data_input)

忽略此代码中的所有其他问题(您没有要传递到
map
x
,您没有使用
x
f2
接收,混合
池。map
管道
通常是错误的做法),您的最终问题是在工作进程可以读取之前执行阻塞
send
调用

假设您确实希望将
映射
管道
混合使用,解决方案是在开始
发送
之前异步启动
映射
,因此在父级尝试写入时,另一侧有一些东西可以从
管道
读取:

if __name__ == '__main__':
    data_input = read_data()    # large numpy array
    parent_conn, child_conn = Pipe()

    # Use with to avoid needing to explicitly close/join
    with multiprocessing.Pool(processes=8) as p:
        func = partial(f2, child_conn)

        # Launch async map to ensure workers are running
        future = p.map_async(func, x)

        # Can perform blocking send as workers will consume as you send
        parent_conn.send(data_input)
        parent_conn.close()

        # Now you can wait on the map to complete
        result = future.get()
如前所述,由于
x
的问题,此代码将不会运行,
Pipe
文档明确警告不应同时从
管道读取两个不同的进程

如果您想在单个辅助进程中批量处理数据,只需使用
process
Pipe
,类似于:

def f2(conn):
    data = conn.recv()
    conn.close()
    print(data)

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()

    proc = multiprocessing.Process(target=f2, args=(child_conn,))
    proc.start()

    data_input = read_data()    # large numpy array
    parent_conn.send(data_input)
    parent_conn.close()

    proc.join()
如果您想在多个工作区中分别处理每个元素,只需使用
Pool
map

def f2(x):
    print(x)

if __name__ == '__main__':
    data_input = read_data()    # large numpy array
    with multiprocessing.Pool(processes=8) as p:   
        result = p.map(f2, data_input)

你为什么要在这里把
管道
地图
混在一起?您的工作人员不使用它接收的
x
,正在传递的
x
不存在,等等。您通常希望将
管道
与一个或多个手动启动的
进程
es或
池上的
映射
一起使用,不是两者都有。@ShadowRanger:原始程序计算一个子进程池,其中x作为单个输入(我将编辑我的帖子)。你的意思是我可以把我的numpy数组作为f2()的参数传递吗?实际上,假设你在一个可以
fork
(读:不是Windows)的系统上,你最好不要传递
numpy
数组。只要
data\u input
在工作线程分叉之前被初始化,它就会被映射到每个子线程的写时拷贝内存中,这样他们就可以访问
f2
中的
data\u input
,它将是调用
进程
时父线程中内容的完美副本。使用
Pool.map
将其作为参数传递给
f2
,需要对数据进行酸洗、传输和取消勾选,其中
fork
s“free”copy效率更高。为什么在这里尝试将
Pipe
map
混合使用?您的工作人员不使用它接收的
x
,正在传递的
x
不存在,等等。您通常希望将
管道
与一个或多个手动启动的
进程
es或
池上的
映射
一起使用,不是两者都有。@ShadowRanger:原始程序计算一个子进程池,其中x作为单个输入(我将编辑我的帖子)。你的意思是我可以把我的numpy数组作为f2()的参数传递吗?实际上,假设你在一个可以
fork
(读:不是Windows)的系统上,你最好不要传递
numpy
数组。只要
data\u input
在工作线程分叉之前被初始化,它就会被映射到每个子线程的写时拷贝内存中,这样他们就可以访问
f2
中的
data\u input
,它将是调用
进程
时父线程中内容的完美副本。使用
Pool.map
将其作为参数传递给
f2
,需要对数据进行酸洗、传输和取消酸洗,其中
fork
s“free”copy效率更高。