这里的简单答案是:不要使用subprocess.Popen,使用
multiprocessing.Process.或者,更好的是,multiprocessing.Pool或
concurrent.futures.ProcessPoolExecutor.
使用子进程,程序的Python解释器根本不了解子进程;据它所知,子进程正在运行Doom.所以没有办法直接与它共享信息.*但是通过多处理,Python控件启动子流程并设置所有内容,以便您可以尽可能方便地共享数据.
不幸的是,“尽可能方便”仍然不像在一个过程中那样方便100%.但你能做的通常是足够好的.阅读Exchanging objects between processes部分和以下几节;希望其中一个机制正是您所需要的.
但是,正如我在顶部隐含的那样,在大多数情况下,您可以通过使用池来使其更简单.不要考虑“运行6个进程并与它们共享数据”,而是将其视为“在6个进程池上运行一堆任务”.任务基本上只是一个函数 – 它接受参数,并返回一个值.如果您要并行化的工作适合该模型 – 听起来就像您的工作一样 – 生活就像生活一样简单.例如:
import multiprocessing
import os
import sys
import analysis
parent_dir = os.path.realpath(sys.argv[0])
paths = [os.path.join(folderpath, file)
for file in os.listdir(folderpath)]
with multiprocessing.Pool(processes=6) as pool:
results = pool.map(analysis.analyze, paths)
如果您使用的是Python 3.2或更早版本(包括2.7),则不能在with语句中使用Pool.我相信你想要这个:**
pool = multiprocessing.Pool(processes=6)
try:
results = pool.map(analysis.analyze, paths)
finally:
pool.close()
pool.join()
这将启动6个进程,***然后告诉第一个进行分析.分析(路径[0]),第二个做分析.分析(路径[1])等.一旦任何进程完成后,游泳池将为其提供下一个工作路径.当它们全部完成后,您将获得所有结果的列表.****
当然,这意味着生活在analysis.py中的顶级代码必须移动到函数def analyze(path)中:所以你可以调用它.或者,更好的是,如果您确实要保存该导入行,则可以将该函数移动到主脚本中,而不是单独的文件中.
*你仍然可以间接地共享信息,例如,将它编组成一些交换格式,如JSON,并通过stdin / stdout管道,文件,共享内存段,套接字等传递它,但是多处理有效地包含了这些信息.你要让它变得更容易.
**关闭池有不同的方法,你也可以选择是否立即加入它,所以你真的应该在某些时候阅读细节.但是当你所做的只是调用pool.map时,它确实没关系;保证游泳池关闭并准备好在地图呼叫返回时立即加入.
***我不确定你为什么要6;大多数机器有4个,8个或16个核心,而不是6个;为什么不全部使用它们?最好的做法通常是完全省略进程= 6并让多处理器向你的操作系统询问使用多少内核,这意味着它仍然可以在你的新机器上全速运行,内核数量是你的两倍.明年会买.
****这有点过于简单;通常,池会为第一个进程提供一批文件,而不是一次一个,以节省一些开销,如果需要优化或更仔细地对它们进行优化,则可以手动控制批处理.但通常你不在乎,这种过度简化是好的.