我正在尝试为此循环实现多处理。它无法修改数组,或者似乎没有正确排序作业(在最后一个函数完成之前返回数组)。
import multiprocessing
import numpy
def func(i, array):
array[i] = i**2
print(i**2)
def main(n):
array = numpy.zeros(n)
if __name__ == '__main__':
jobs = []
for i in range(0, n):
p = multiprocessing.Process(target=func, args=(i, array))
jobs.append(p)
p.start()
return array
print(main(10))
答案 0 :(得分:5)
进程不共享内存,程序最初将创建一个满零的数组,然后启动10个进程,这将在数组首次创建时调用func函数,但从不调用原始数组。< / p>
您似乎真正想要实现的目标是:
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)
这是一种流行的模式,使用asyncio事件循环来并行完成任务。但是,由于您正在使用像Numpy这样的库,我质疑这种模式对您有多大价值。
答案 1 :(得分:3)
之前我没有使用multiprocessing
所以我也是新手,但经过一些研究(主要来自these two帖子),我想我已经部分设法使用此代码解决您的问题:
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.]
这种方法修改数组的原因并没有在this answer that I referenced in the comments中解释:
问题在于,当对象被传递给工作进程时,它们被打包并运送到另一个进程,在那里它们被解压缩并进行处理。您的对象不会像克隆那样传递给其他进程。您不会返回对象,因此克隆的对象会被愉快地修改,然后被丢弃。
关于我的(部分)解决方案,我应该指出一些事项:
此实现运行很多比仅以常规方式生成此列表(通过单个线程)慢。这很可能是由于在它们之间创建新流程和编组数据所增加的开销。
由于您的问题的性质(具有每个修改数组的作业),每个作业必须将上一个作业的输出作为输入。由于这种限制,我认为不可能同时运行作业,这种做法会使多处理失败。
至于后两点,我确实尝试了一种变体,其中func
返回一个函数,它接受一个数组并返回它的修改版本。这将允许作业同时运行,但不幸的是,它似乎不能被腌制。