python pool.map()和共享数组变量

时间:2019-06-13 16:43:07

标签: python python-3.x multithreading multiprocessing

我有一个线程池,每个线程都应该可以访问一个数组。不幸的是,这没有按照我的想法工作。这是一个最小的代码片段:

#!/usr/bin/python3

import multiprocessing

class MyClass():

    shared = []
    l = multiprocessing.Lock()

    def __init__(self):
        with multiprocessing.Pool(processes=2) as pool:
            pool.map(self.mythread, range(1,10))

        print(self.shared)


    def mythread(self, param):
        print(param)
        self.l.acquire()
        self.shared.append(param)
        print(self.shared)
        self.l.release()


if __name__ == "__main__":
    instance = MyClass()

我希望最后一个输出包含所有数字,但事实并非如此,它甚至是空的。此外,似乎我在中间数组状态中丢失了数字。我认为不可能有比赛条件。 输出:

1
[1]
2
[1, 2]
3
[3]
4
[3, 4]
5
[1, 2, 5]
6
[1, 2, 5, 6]
9
7
[1, 2, 5, 6, 9]
[3, 4, 7]
8
[3, 4, 7, 8]
[]

1 个答案:

答案 0 :(得分:0)

您所做的不正确。可以使用多个线程,因为它们共享内存,但是多个进程不共享内存!内存被复制到子进程,因此每个进程都有其自己的“共享”数组副本,而主进程具有从未被触及的原始副本。

multiprocessing模块确实have some facilities to handle shared state,但是请注意,共享对象比普通的python对象要慢。相反,通常使子进程完全独立并使主进程最终重组输出更为容易。

根据您的情况,您可以使用Manager对象实例化共享列表:

import multiprocessing

class MyClass():

    shared = []
    l = multiprocessing.Lock()

    def __init__(self):
        with multiprocessing.Manager() as manager, multiprocessing.Pool(processes=2) as pool:
            self.shared = manager.list([])
            pool.map(self.mythread, range(1,10))

        print(self.shared)


    def mythread(self, param):
        print(param)
        self.l.acquire()
        self.shared.append(param)
        print(self.shared)
        self.l.release()


if __name__ == "__main__":
    instance = MyClass()

但这可能会更快:

import multiprocessing

class MyClass():


    def __init__(self):
        with multiprocessing.Pool(processes=2) as pool:
            results = pool.map(self.mythread, range(1,10))
            final_result = [x for res in results for x in res]
        print(final_result)


    def mythread(self, param):
        print(param)
        # assume that this might return more than one value
        return [param, ...]


if __name__ == "__main__":
    instance = MyClass()

顺便说一句:如果在map处应用的functin的结果与其他子过程无关,并且仅具有一个结果,则仅使用map即可返回值列表你想要的。