Python多进程:进程间共享数据

3

我第一次尝试使用多进程技术,遇到了一些基础问题。以下是一个简单的示例,其中有两个进程在向列表中添加数据:

def add_process(all_nums_class, numbers_to_add):
    for number in numbers_to_add:
        all_nums_class.all_nums_list.append(number)

class AllNumsClass:
    def __init__(self):
        self.all_nums_list = []

all_nums_class = AllNumsClass()

p1 = Process(target=add_process, args=(all_nums_class, [1,3,5]))
p1.start()

p2 = Process(target=add_process, args=(all_nums_class, [2,4,6]))
p2.start()

all_nums_class.all_nums_list

我希望这些进程之间共享 all_nums_class,以便它们都可以向其 all_nums_list 添加内容 - 所以结果应该是

[1,2,3,4,5,6]

不再继续获得老旧的东西,而是获取更先进的内容。

[]

请问有人能给予建议吗?我稍微尝试了一下命名空间,但是还没有成功。

我觉得最好提一下(如果有影响的话),我是在Jupyter笔记本上进行操作的。

1个回答

9
您可以使用多进程队列或管道来在进程之间共享数据。队列既适用于线程也适用于进程。当使用管道时,如果两个进程(或线程)同时尝试从管道的同一端读取或写入数据,则管道中的数据可能会损坏,因此您需要更加小心。当然,如果进程同时使用管道的不同端口,则不存在损坏的风险。

目前,您的实现每个进程都有自己的self.all_nums_list,所以您实际上会生成三个AllNumsClass对象:一个在主程序中,一个在p1中,另一个在p2中。由于进程是独立的并且不共享相同的内存空间,它们确实正在正确地附加,但对于每个进程,它们正在附加到自己的self.all_nums_list。这就是为什么当您在主程序中打印all_nums_class.all_nums_list时,您打印的是主进程的self.all_nums_list,它是一个空列表。为了共享数据并使进程附加到同一列表中,我建议使用队列。

使用队列和进程的示例

import multiprocessing as mp

def add_process(queue, numbers_to_add):
    for number in numbers_to_add:
        queue.put(number)

class AllNumsClass:
    def __init__(self):
        self.queue = mp.Queue()
    def get_queue(self):
        return self.queue

if __name__ == '__main__':
    
    all_nums_class = AllNumsClass()

    processes = []
    p1 = mp.Process(target=add_process, args=(all_nums_class.get_queue(), [1,3,5]))
    p2 = mp.Process(target=add_process, args=(all_nums_class.get_queue(), [2,4,6]))

    processes.append(p1)
    processes.append(p2)
    for p in processes:
        p.start()
    for p in processes:
        p.join()

    output = [] 
    while all_nums_class.get_queue().qsize() > 0:
        output.append(all_nums_class.get_queue().get())
    print(output)

这个实现是异步的,因为它不是按顺序执行的。每次运行时,你可能会得到不同的输出。 示例输出

[1, 2, 3, 5, 4, 6]

[1, 3, 5, 2, 4, 6]

[2, 4, 6, 1, 3, 5]

[2, 1, 4, 3, 5, 6]

维护有序或无序结果列表的更简单方法是使用mp.Pool类,特别是Pool.applyPool.apply_async函数。 Pool.apply将锁定主程序,直到所有进程完成,这在某些应用程序中想要按特定顺序获取结果时非常有用。相反,Pool.apply_async将一次性提交所有进程,并在它们完成后立即检索结果。另一个区别是我们需要在Pool.apply_async调用后使用get方法以获取完成进程的返回值。


谢谢 - 我现在正在尝试调整这个。我对队列的理解是两个进程不能同时处理同一个类,所以我应该能够得到[1,3,5,2,4,6]的结果,但不是[1,2,3,4,5,6]。我的理解正确吗?如果是这样,您知道在它们运行时是否有一种共享数据的方法吗? - Chris J Harris
我提供了一个使用相同 mp.Queue 的类的示例。据我所知,两个进程可以同时在同一个队列对象上工作,这是可能的,因为 mp.Queue 是线程/进程安全的。我认为它们能够在两个进程之间共享数据。就个人而言,我认为 mp.Queue 就像是在两个进程之间共享的全局变量,但我可能是错的。 - nathancy
谢谢你,这真的很有帮助。看起来 mp.Queue 是一个不错的选择。 - Chris J Harris
我通常在进行多进程处理时使用mp.Queue,但mp.Array也很好。 - nathancy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接