代码之家  ›  专栏  ›  技术社区  ›  Bram Vanroy

线程池执行器、进程池执行器和全局变量

  •  1
  • Bram Vanroy  · 技术社区  · 7 年前

    我不熟悉一般的并行化,特别是并发的期货。我想对我的脚本进行基准测试,比较使用线程和进程之间的差异,但是我发现我甚至无法运行它,因为当使用 ProcessPoolExecutor 我不能使用全局变量。

    将输出以下代码 Hello 如我所料,但当你改变 ThreadPoolExecutor 对于 进程池执行器 ,它将输出 None .

    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    
    greeting = None
    
    def process():
        print(greeting)
    
        return None
    
    
    def main():
        with ThreadPoolExecutor(max_workers=1) as executor:
            executor.submit(process)
    
        return None
    
    
    def init():
        global greeting
        greeting = 'Hello'
    
        return None
    
    if __name__ == '__main__':
        init()
        main()
    

    我不明白为什么会这样。在我的实际程序中,init用于将全局变量设置为cli参数,其中有很多参数。因此,似乎不建议将它们作为参数传递。那么,如何正确地将这些全局变量传递给每个进程/线程呢?

    我知道我可以改变周围的事情,这会起作用,但我不明白为什么。例如,以下内容适用于两个执行者,但也意味着全局初始化必须在每个实例中进行。

    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    
    greeting = None
    
    def init():
        global greeting
        greeting = 'Hello'
    
        return None
    
    
    def main():
        with ThreadPoolExecutor(max_workers=1) as executor:
            executor.submit(process)
    
        return None
    
    def process():
        init()
        print(greeting)
    
        return None
    
    if __name__ == '__main__':
        main()
    

    所以我的主要问题是, 到底发生了什么 .为什么此代码与线程一起工作而不是与进程一起工作?而且,如何正确地将set globals传递给每个进程/线程,而不必为每个实例重新初始化它们?

    (旁注:因为我已经阅读过concurrent.futures在Windows上的行为可能不同,所以我必须注意,我在Windows10 64位上运行的是python 3.6。)

    3 回复  |  直到 7 年前
        1
  •  0
  •   jedwards    7 年前

    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    
    def process(opts):
        opts["process"] = "got here"
        print("In process():", opts)
    
        return None
    
    
    def main(opts):
        opts["main"] = "got here"
        executor = [ProcessPoolExecutor, ThreadPoolExecutor][1]
        with executor(max_workers=1) as executor:
            executor.submit(process, opts)
    
        return None
    
    
    def init(opts):                         # Gather CLI opts and populate dict
        opts["init"] = "got here"
    
        return None
    
    
    if __name__ == '__main__':
        cli_opts = {"__main__": "got here"} # Initialize dict
        init(cli_opts)                      # Populate dict
        main(cli_opts)                      # Use dict
    

    编辑:尽管这听起来对您的用例来说不会有问题,但我会指出 ProcessPoolExecutor opts 听写你进去了 process __main__ 阻止。 ThreadPoolExecutor

        2
  •  0
  •   Sraw    7 年前

    因此,当您使用线程时,您将为当前框(主进程)创建多个工作线程。但当您使用过程时,您正在创建另一个框。在这种情况下,此框中初始化的全局变量与另一个框中的全局变量完全不同。这就是为什么它不能像你期望的那样工作。

        3
  •  0
  •   shmee    7 年前

    进程表示在操作系统中独立进程中运行的活动,这意味着线程都在主进程中运行。每个进程都有自己独特的命名空间。

    greeting init() 在你的 __name__ == '__main__' __name__ '__mp_name__'

    虽然通常不建议在进程之间共享状态,但有一些方法可以这样做,如@jedwards answer中所述。

    Sharing State Between Processes 从文件中。

    推荐文章