如何将 parent 中的变量传递给 python 中的子进程?
How to pass variables in parent to subprocess in python?
我正在尝试让 parent python 脚本将变量发送到 child 脚本以帮助我 speed-up 和自动化视频分析。
我现在正在使用 subprocess.Popen()
调用 start-up 6 个 child 脚本实例,但无法找到一种方法来传递已在 [=32 中调用的变量和模块=] 到 child。例如,parent 文件将具有:
import sys
import subprocess
parent_dir = os.path.realpath(sys.argv[0])
subprocess.Popen(sys.executable, 'analysis.py')
但 import sys; import subprocess; parent_dir
必须在 "analysis.py" 中再次调用。有没有办法将它们传递给 child?
简而言之,我想要实现的是:我有一个包含数百个视频文件的文件夹。我希望 parent python 脚本列出视频文件并启动最多 6 个分析脚本的并行实例,每个实例分析一个视频文件。如果没有更多文件要分析,parent 文件将停止。
这里的简单答案是:不要使用 subprocess.Popen
,使用 multiprocessing.Process
. Or, better yet, multiprocessing.Pool
or concurrent.futures.ProcessPoolExecutor
。
使用 subprocess
,您程序的 Python 解释器根本不知道有关子进程的任何信息;就其所知,子进程是 运行ning Doom。所以没有办法直接与它共享信息。* 但是 multiprocessing
,Python 控制启动子进程并设置所有内容,以便您可以尽可能方便地共享数据。
不幸的是,"as conveniently as possible" 仍然不是 100% 像在一个进程中那样方便。但你能做的通常已经足够好了。阅读有关 Exchanging objects between processes 的部分和以下几部分;希望其中一种机制正是您所需要的。
但是,正如我在顶部暗示的那样,在大多数情况下,您可以通过使用池使它变得更简单。与其考虑 "running 6 processes and sharing data with them",不如将其视为 "running a bunch of tasks on a pool of 6 processes"。任务基本上只是一个函数——它接受参数,returns 一个值。如果您想要并行化的工作适合该模型——听起来就像您的工作一样——生活就会尽可能简单。例如:
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 个进程,*** 然后告诉第一个执行 analysis.analyze(paths[0])
,第二个执行 analysis.analyze(paths[1])
,等等。一旦任何进程完成, pool 将为它提供下一个工作路径。当它们全部完成后,您会得到所有结果的列表。****
当然,这意味着 analysis.py
中的顶级代码必须移动到函数 def analyze(path):
中,以便您可以调用它。或者,更好的是,如果您真的想保存那行 import
,您可以将该函数移动到主脚本中,而不是单独的文件中。
* 您仍然可以 间接地 共享信息,例如,将其编组为某种交换格式,如 JSON 并通过 stdin/stdout 管道、文件、共享内存段、套接字等,但 multiprocessing
有效地将其包装起来,让您更轻松。
** 有多种关闭池的方法,您也可以选择是否立即加入,所以您真的应该在某个时候阅读详细信息。但是当你所做的只是调用 pool.map
时,这真的无关紧要;到 map
调用 returns.
时,池保证关闭并几乎立即准备好加入
*** 我不知道你为什么要 6;大多数机器有 4、8 或 16 个内核,而不是 6 个;为什么不全部使用它们呢?最好的办法通常是完全忽略 processes=6
,让 multiprocessing
询问您的 OS 要使用多少个核心,这意味着它仍然 运行 在在新机器上全速运行,内核数量是明年购买的两倍。
**** 这有点过于简单了;通常池会给第一个进程一批文件,而不是一次一个,以节省一些开销,如果您需要优化事物或更仔细地排序它们,您可以手动控制批处理。但通常你不在乎,这种过于简单化是可以的。
我正在尝试让 parent python 脚本将变量发送到 child 脚本以帮助我 speed-up 和自动化视频分析。
我现在正在使用 subprocess.Popen()
调用 start-up 6 个 child 脚本实例,但无法找到一种方法来传递已在 [=32 中调用的变量和模块=] 到 child。例如,parent 文件将具有:
import sys
import subprocess
parent_dir = os.path.realpath(sys.argv[0])
subprocess.Popen(sys.executable, 'analysis.py')
但 import sys; import subprocess; parent_dir
必须在 "analysis.py" 中再次调用。有没有办法将它们传递给 child?
简而言之,我想要实现的是:我有一个包含数百个视频文件的文件夹。我希望 parent python 脚本列出视频文件并启动最多 6 个分析脚本的并行实例,每个实例分析一个视频文件。如果没有更多文件要分析,parent 文件将停止。
这里的简单答案是:不要使用 subprocess.Popen
,使用 multiprocessing.Process
. Or, better yet, multiprocessing.Pool
or concurrent.futures.ProcessPoolExecutor
。
使用 subprocess
,您程序的 Python 解释器根本不知道有关子进程的任何信息;就其所知,子进程是 运行ning Doom。所以没有办法直接与它共享信息。* 但是 multiprocessing
,Python 控制启动子进程并设置所有内容,以便您可以尽可能方便地共享数据。
不幸的是,"as conveniently as possible" 仍然不是 100% 像在一个进程中那样方便。但你能做的通常已经足够好了。阅读有关 Exchanging objects between processes 的部分和以下几部分;希望其中一种机制正是您所需要的。
但是,正如我在顶部暗示的那样,在大多数情况下,您可以通过使用池使它变得更简单。与其考虑 "running 6 processes and sharing data with them",不如将其视为 "running a bunch of tasks on a pool of 6 processes"。任务基本上只是一个函数——它接受参数,returns 一个值。如果您想要并行化的工作适合该模型——听起来就像您的工作一样——生活就会尽可能简单。例如:
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 个进程,*** 然后告诉第一个执行 analysis.analyze(paths[0])
,第二个执行 analysis.analyze(paths[1])
,等等。一旦任何进程完成, pool 将为它提供下一个工作路径。当它们全部完成后,您会得到所有结果的列表。****
当然,这意味着 analysis.py
中的顶级代码必须移动到函数 def analyze(path):
中,以便您可以调用它。或者,更好的是,如果您真的想保存那行 import
,您可以将该函数移动到主脚本中,而不是单独的文件中。
* 您仍然可以 间接地 共享信息,例如,将其编组为某种交换格式,如 JSON 并通过 stdin/stdout 管道、文件、共享内存段、套接字等,但 multiprocessing
有效地将其包装起来,让您更轻松。
** 有多种关闭池的方法,您也可以选择是否立即加入,所以您真的应该在某个时候阅读详细信息。但是当你所做的只是调用 pool.map
时,这真的无关紧要;到 map
调用 returns.
*** 我不知道你为什么要 6;大多数机器有 4、8 或 16 个内核,而不是 6 个;为什么不全部使用它们呢?最好的办法通常是完全忽略 processes=6
,让 multiprocessing
询问您的 OS 要使用多少个核心,这意味着它仍然 运行 在在新机器上全速运行,内核数量是明年购买的两倍。
**** 这有点过于简单了;通常池会给第一个进程一批文件,而不是一次一个,以节省一些开销,如果您需要优化事物或更仔细地排序它们,您可以手动控制批处理。但通常你不在乎,这种过于简单化是可以的。