在 Google Colab 中启动进程,前缀为“!”对比 "subprocess.Popen(..)"

Starting process in Google Colab with Prefix "!" vs. "subprocess.Popen(..)"

我已经使用 Google Colab 几个星期了,我一直想知道以下两个命令之间的区别(例如):

  1. !ffmpeg ...
  2. subprocess.Popen(['ffmpeg', ...

我想知道,因为我 运行 在启动上述任一命令然后尝试中途停止执行时遇到了一些问题。它们都在 KeyboardInterrupt 上取消,但我注意到在那之后运行时需要恢复出厂设置,因为它不知何故卡住了。在 Linux 控制台中检查 ps aux 列出了一个进程 [ffmpeg] <defunct>,不知何故它仍然是 运行 或者至少阻止了一些看起来像的资源。

然后我做了一些研究,发现了一些类似的帖子,询问有关如何正确终止子进程的问题 (1, , 3)。基于这些帖子,我通常得出结论,使用 subprocess.Popen(..) 变体在处理子流程时显然提供了更大的灵活性:定义不同的 stdout 过程或对不同的 returncode 等做出反应。但是我仍然不确定上面使用 ! 作为前缀的第一个命令到底在做什么。

使用第一个命令要容易得多,并且需要更少的代码来启动这个过程。假设我不需要很多逻辑来处理流程,这将是执行类似 ffmpeg 的好方法 - 如果我能够按预期终止它。即使按照使用第二条命令的其他帖子的答案,我也从未达到可以在启动后完全终止进程的地步(即使使用 shell=Falseprocess.kill()process.wait() 等。 ).这让我很沮丧,因为每次重新启动和重新初始化 Colab 实例本身都可能需要几分钟。

所以,最后,我想更笼统地了解区别是什么,并希望有人能启发我。谢谢!

! 命令由笔记本执行(或更具体地说,由 ipython 解释器执行),并且不是有效的 Python 命令。如果您编写的代码需要在 notebook 环境之外工作,则不能使用 ! 命令。

正如您正确指出的那样,您无法与通过 ! 启动的子流程进行交互;因此它也没有显式 subprocess 调用灵活,尽管在这方面类似于 subprocess.call

就像文档中提到的那样,除非您特别需要它提供的详细灵活性,否则您通常应该避免裸露的 subprocess.Popen,代价是必须复制 [=18= 的 higher-level 功能]等。已经实施。 运行 命令并等待它完成的代码很简单

subprocess.check_call(['ffmpeg', ... ])

具有用于捕获其输出的变体 (check_output) 和更现代的 run,它可以轻松替换所有三个遗留 high-level 调用,尽管增加了一些冗长。