为什么 subprocess.Popen 运行 并行但 subprocess.run 不并行
Why does subprocess.Popen run in parallel but subprocess.run does not
我想在子进程中并行执行昂贵的 IO 操作。但是,当我执行以下代码时,它会按顺序运行并需要很长时间才能完成:
import subprocess
import csv
processes = []
with open(f'identifiers.csv', 'r', newline='') as infile:
reader = csv.DictReader(infile)
for row in reader:
id = row['id']
p = subprocess.run(f'expensive_io_operation {id}', shell=True)
processes.append(p)
for process in processes:
process.wait()
此代码块按顺序运行。
但是,如果我将 subprocess.run
替换为 subprocess.Popen
,那么这段代码将并行执行。
我想知道为什么。
这有明确的记录; subprocess.run
阻塞并等待子进程完成。如果你想运行一个并行子进程,你需要Popen
;但是您还需要对 run
在幕后为您处理的子流程对象进行必要的管理。 (事实上,run
返回的 CompletedProcess
对象显然没有 wait
方法,因为,呃,它已经完成了。)
切线地说,如果速度很重要,你真的要避免完全多余的 shell=True
;在 Unix-like 系统上,您需要将命令分解为字符串列表(或使用 shlex.split()
)。
p = child_processes.Popen(['expensive_io_operation', id])
在这种情况下,将各个部分粘合成一根绳子以便需要 shell 将它们再次分开显然也是不必要的,而且有点浪费。
如果昂贵的操作是 I/O 绑定的,则必须小心添加并行处理的位置。在已经使 I/O 带宽饱和的问题上投入更多 CPU 只会增加拥塞,并使速度变慢。
也许还可以查看 multiprocessing
,它可以处理 运行 宁 受控 数量的并行任务并收集它们的结果。使用 multiprocessing.Pool
和一个队列,您可以 运行,比如 16 个并行进程,并根据它们的可用性从队列中分配任务,而无需 nitty-gritty 管理个人自己处理。
最后,对于 I/O,其中许多任务涉及大量等待,或许可以查看 async
,它可以让您通过划分工作在单个进程中实现(明显的)并行性进入 non-blocking 片段,其中 Python 负责在它们到达 await
语句(或其他;这个简短的说明显然被删节)时在它们之间切换。
我想在子进程中并行执行昂贵的 IO 操作。但是,当我执行以下代码时,它会按顺序运行并需要很长时间才能完成:
import subprocess
import csv
processes = []
with open(f'identifiers.csv', 'r', newline='') as infile:
reader = csv.DictReader(infile)
for row in reader:
id = row['id']
p = subprocess.run(f'expensive_io_operation {id}', shell=True)
processes.append(p)
for process in processes:
process.wait()
此代码块按顺序运行。
但是,如果我将 subprocess.run
替换为 subprocess.Popen
,那么这段代码将并行执行。
我想知道为什么。
这有明确的记录; subprocess.run
阻塞并等待子进程完成。如果你想运行一个并行子进程,你需要Popen
;但是您还需要对 run
在幕后为您处理的子流程对象进行必要的管理。 (事实上,run
返回的 CompletedProcess
对象显然没有 wait
方法,因为,呃,它已经完成了。)
切线地说,如果速度很重要,你真的要避免完全多余的 shell=True
;在 Unix-like 系统上,您需要将命令分解为字符串列表(或使用 shlex.split()
)。
p = child_processes.Popen(['expensive_io_operation', id])
在这种情况下,将各个部分粘合成一根绳子以便需要 shell 将它们再次分开显然也是不必要的,而且有点浪费。
如果昂贵的操作是 I/O 绑定的,则必须小心添加并行处理的位置。在已经使 I/O 带宽饱和的问题上投入更多 CPU 只会增加拥塞,并使速度变慢。
也许还可以查看 multiprocessing
,它可以处理 运行 宁 受控 数量的并行任务并收集它们的结果。使用 multiprocessing.Pool
和一个队列,您可以 运行,比如 16 个并行进程,并根据它们的可用性从队列中分配任务,而无需 nitty-gritty 管理个人自己处理。
最后,对于 I/O,其中许多任务涉及大量等待,或许可以查看 async
,它可以让您通过划分工作在单个进程中实现(明显的)并行性进入 non-blocking 片段,其中 Python 负责在它们到达 await
语句(或其他;这个简短的说明显然被删节)时在它们之间切换。