代码之家  ›  专栏  ›  技术社区  ›  Tomas

Python多重处理。池和参数酸洗

  •  3
  • Tomas  · 技术社区  · 6 年前

    考虑以下示例:

    import multiprocessing as mp
    
    def job(l):
        l.append(1)
        return l
    
    if __name__ == "__main__":
        pool = mp.Pool(1)
        my_list = []
        out = pool.map(job, [my_list for i in range(5)])
        pool.close()
        pool.join()
        print(out)
    

    [[1, 1], [1, 1], [1, 1], [1, 1], [1]]
    

    有人能解释一下发生了什么事吗?我希望输出是 是一个由五个[1]或[1],[1,1],…,[1,1,1,1]]组成的列表,两者都不是。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Darkonaut    6 年前

    这个 chunksize 的参数 pool.map 是你困惑的原因。显然,它会选择为您的设置自动设置chunksize=2,因为您也可以通过显式设置获得您观察到的输出 chunksize=2 .

    chunksize=1 你会得到 [[1], [1], [1], [1], [1]] chunksize=3 [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1], [1, 1]] .

    如果用打印扩展代码,可以观察发生了什么:

    import multiprocessing as mp
    
    def job(l):
        print(f'before append {l}')
        l.append(1)
        print(f'after append {l}')
        return l
    
    if __name__ == "__main__":
        pool = mp.Pool(1)
        my_list = []
        out = pool.map(job, [my_list for _ in range(5)], chunksize=2)
        pool.close()
        pool.join()
        print(out)
    

    这将为您提供以下输出:

    before append []
    after append [1]
    before append [1]
    after append [1, 1]
    before append []
    after append [1]
    before append [1]
    after append [1, 1]
    before append []
    after append [1]
    [[1, 1], [1, 1], [1, 1], [1, 1], [1]]
    
    Process finished with exit code 0
    

    在iterable中有5个项目,你有5/2=2.5个任务。半个任务是不可能的,所以这就是为什么你最终会有3个任务:两个任务有两个项目块,一个任务有一个项目块。

    现在,对于前两个任务,函数的第一次执行 job 1 . 然后第二次执行得到与第一次执行刚刚修改的列表相同的列表,因为您的项只是对该任务中相同列表的引用。第二次执行也会更改第一次执行的结果,因为两者都修改相同的基础对象。第二次执行后,任务完成,两次执行的结果[[1,1],[1,1]]被发送回父级。正如我们所说,前两项任务都是这样。

    第三个任务只有一次执行 工作

    如果你加上 for obj in out: print(id(obj))

    140584841382600
    140584841382600
    140584841383432
    140584841383432
    140584841383368
    
        2
  •  0
  •   kungphu    6 年前

    这就产生了不同进程数的不同结果,这意味着你在做一些进程不安全的事情;在这种情况下,在(可能)多个进程中对本机列表进行操作。

    from multiprocessing import Pool, Manager
    
    
    def job(l):
        l.append(1)
        return l
    
    
    if __name__ == "__main__":
        manager = Manager()
    
        for proc_count in range(1, 6):
            print(proc_count)
            pool = Pool(proc_count)
            my_list = manager.list()
            out = pool.map(job, [my_list for i in range(5)])
            pool.close()
            pool.join()
            print(list(list(o) for o in out))
    

    如果这不是你想要的,忘记经理,放弃 my_list 以及使用 [list() for i in range(5)]