多处理在python中写入数组的函数的循环

多处理在python中写入数组的函数的循环,python,arrays,loops,multiprocessing,Python,Arrays,Loops,Multiprocessing,我正在尝试为这个循环实现多处理。它无法修改数组或,并且似乎无法正确排序作业(返回上一个函数完成之前的数组) 我以前没有使用过多处理,所以我对这一点也不熟悉,但在做了一些研究(主要是从帖子中),我想我已经部分地解决了您使用此代码的问题: import multiprocessing import numpy def func(i, array, connection): squared_value = i ** 2 array[i] = squared_value pr

我正在尝试为这个循环实现多处理。它无法修改数组或,并且似乎无法正确排序作业(返回上一个函数完成之前的数组)


我以前没有使用过
多处理
,所以我对这一点也不熟悉,但在做了一些研究(主要是从帖子中),我想我已经部分地解决了您使用此代码的问题:

import multiprocessing
import numpy


def func(i, array, connection):
    squared_value = i ** 2
    array[i] = squared_value
    print(squared_value)

    connection.send(array)


def main(n):
    array = numpy.zeros(n)

    for i in range(0, n):
        recv_end, send_end = multiprocessing.Pipe(False)
        p = multiprocessing.Process(target=func, args=(i, array, send_end))
        p.start()
        p.join()
        array = recv_end.recv()

    return array


if __name__ == '__main__':
    print(main(10))
输出

0
1.
4.
9
16
25
36
49
64
81
[  0.   1.   4.   9.  16.  25.  36.  49.  64.  81.]
此方法修改阵列而您的方法不修改阵列的原因解释如下:

问题是,当对象被传递到工作进程时,它们会被打包成pickle,然后被运送到另一个进程,在那里它们会被解包并处理。您的对象与其说是传递给另一个进程,不如说是克隆。您不返回对象,因此克隆的对象被愉快地修改,然后丢弃

关于我的(部分)解决方案,我应该指出以下几点:

  • 此实现的运行速度比仅以常规方式(通过单个线程)生成此列表要慢得多。这很可能是由于创建新进程和在它们之间编组数据所增加的开销

  • 由于问题的性质(每个作业都修改一个数组),每个作业都必须将上一个作业的输出作为输入。由于这个限制,我认为不可能让作业同时运行,这有点违背了多处理的观点


至于这两点中的后一点,我尝试了一个变体,其中
func
返回一个接受数组并返回其修改版本的函数。这将允许作业同时运行,但不幸的是,函数似乎不能被pickle。

进程不共享内存,您的程序最初将创建一个满是零的数组,然后启动10个进程,这些进程将在首次创建数组时对数组的副本调用func函数,但决不是原始数组

看起来你真正想要实现的是:

from multiprocessing import Process, Lock
from multiprocessing.sharedctypes import Array


def modify_array(index, sharedarray):
    sharedarray[index] = index ** 2
    print([x for x in sharedarray])


def main(n):
    lock = Lock()
    array = Array('i', 10, lock=lock)
    if __name__ == '__main__':
        for i in range(0, n):
            p = Process(target=modify_array, args=(i, array))
            p.start()
            p.join()
    return list(array)

main(10)
输出:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 4, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 4, 9, 0, 0, 0, 0, 0, 0]
[0, 1, 4, 9, 16, 0, 0, 0, 0, 0]
[0, 1, 4, 9, 16, 25, 0, 0, 0, 0]
[0, 1, 4, 9, 16, 25, 36, 0, 0, 0]
[0, 1, 4, 9, 16, 25, 36, 49, 0, 0]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 0]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
但问题是,使用多处理是错误的。与新线程相比,生成一个额外的进程,甚至只是保持单线程状态并利用事件循环触发操作,都会有很大的开销

在Python的单线程单进程中使用并发的示例如下所示:

import numpy as np
from asyncio import get_event_loop, wait, ensure_future


def modify_array(index, array):
    array[index] = index ** 2
    print([x for x in array])


async def task(loop, function, index, array):
    await loop.run_in_executor(None, function, index, array)


def main(n):
    loop = get_event_loop()
    jobs = list()
    array = np.zeros(10)
    for i in range(0, n):
        jobs.append(
            ensure_future(
                task(loop, modify_array, i, array)
            )
        )
    loop.run_until_complete(wait(jobs))
    loop.close()

main(10)

这是目前流行的一种模式,即使用异步IO事件循环并行完成任务。但是,由于您使用的是Numpy之类的库,我怀疑此模式对您的价值有多大。

From:“问题是,当对象被传递到工作进程时,它们会用pickle打包,然后运送到另一个进程,在那里它们会被解包并处理。您的对象与其说是传递给另一个进程,不如说是克隆。“这是我的回答之外的另一个选择。比我快。“我对速度也做了同样的观察。”瓦西里西拉基斯,谢谢。知道
多处理
定义了可以在进程之间共享的类型是很酷的+谢谢你的回复。我正在测试您的响应,在函数中添加一个循环以增加处理时间。(对于范围(010000)中的j,sum=0///sum=sum+j)。它仍然在单核上连续执行功能-我是否需要做一些额外的事情,使它在每个CPU核上运行一个进程?感谢您的回复。我可以访问一台30核的机器,我的实际函数包含一个积分,大约需要2秒(完成数千次)。在这种情况下,开销是否值得,或者还有更好的方法吗?如果任务在开始时生成长时间运行的进程,那么开销可能不是问题,但是如果您经常生成进程,我会说这不值得。您的程序还会给出错误消息raise RUNTIMERROR('Event loop is closed')运行时错误:事件循环已关闭
import numpy as np
from asyncio import get_event_loop, wait, ensure_future


def modify_array(index, array):
    array[index] = index ** 2
    print([x for x in array])


async def task(loop, function, index, array):
    await loop.run_in_executor(None, function, index, array)


def main(n):
    loop = get_event_loop()
    jobs = list()
    array = np.zeros(10)
    for i in range(0, n):
        jobs.append(
            ensure_future(
                task(loop, modify_array, i, array)
            )
        )
    loop.run_until_complete(wait(jobs))
    loop.close()

main(10)