如何将父变量传递给python中的子进程?

时间:2015-04-13 08:36:46

标签: python subprocess

我正在尝试让父python脚本将变量发送到子脚本,以帮助我加速和自动化视频分析。

我现在正在使用subprocess.Popen()调用启动子脚本的6个实例,但无法找到将父级中已调用的变量和模块传递给子级的方法。例如,父文件将具有:

import sys
import subprocess
parent_dir = os.path.realpath(sys.argv[0])
subprocess.Popen(sys.executable, 'analysis.py')

但是必须在" analysis.py"中再次调用import sys; import subprocess; parent_dir。有没有办法将它们传给孩子?

简而言之,我想要实现的是:我有一个包含几百个视频文件的文件夹。我希望父python脚本列出视频文件并启动分析脚本的6个并行实例,每个实例分析一个视频文件。如果没有更多要分析的文件,则父文件将停止。

1 个答案:

答案 0 :(得分:13)

这里的简单答案是:不要使用subprocess.Popen,请使用multiprocessing.Process。或者,更好的是multiprocessing.Poolconcurrent.futures.ProcessPoolExecutor

使用subprocess,程序的Python解释器根本不了解子进程;据它所知,子进程正在运行Doom。所以没有办法直接与它共享信息。*但是使用multiprocessing,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),则无法在Pool语句中使用with。我相信你想要这个:**

pool = multiprocessing.Pool(processes=6)
try:
    results = pool.map(analysis.analyze, paths)
finally:
    pool.close()
    pool.join()

这将启动6个进程,***然后告诉第一个进程analysis.analyze(paths[0]),第二个执行analysis.analyze(paths[1])等等。一旦任何进程完成,池将会给它下一个工作路径。当他们全部完成后,你会得到所有结果的清单。****

当然这意味着生成在analysis.py中的顶级代码必须移动到函数def analyze(path):中,以便您可以调用它。或者,更好的是,如果您确实要保存import行,则可以将该函数移动到主脚本中,而不是单独的文件。


*您仍然可以间接共享信息,例如,将其编组为某种交换格式,如JSON,并通过stdin / stdout管道,文件,共享内存段传递,一个套接字等,但multiprocessing有效地包装了你,使它变得更容易。

**关闭池有不同的方法,你也可以选择是否立即加入它,所以你真的应该在某些时候阅读细节。但是当你所做的一切都在呼唤pool.map时,它确实无关紧要;保证池在map调用返回时几乎立即关闭并准备好加入。

***我不确定你为什么要6;大多数机器有4个,8个或16个核心,而不是6个;为什么不全部使用它们?最好的办法通常是完全省略processes=6并让multiprocessing向你的操作系统询问要使用多少核心,这意味着它仍然会在你的新机器上全速运行两次你将在明年购买多少核心。

****这有点过于简单;通常,池会为第一个进程提供一批文件,而不是一次一个,以节省一些开销,如果需要优化或更仔细地对它们进行优化,则可以手动控制批处理。但通常你不在乎,这种过于简单化就好了。