在 Google Colab 中启动进程,前缀为“!”对比 "subprocess.Popen(..)"
Starting process in Google Colab with Prefix "!" vs. "subprocess.Popen(..)"
我已经使用 Google Colab 几个星期了,我一直想知道以下两个命令之间的区别(例如):
!ffmpeg ...
subprocess.Popen(['ffmpeg', ...
我想知道,因为我 运行 在启动上述任一命令然后尝试中途停止执行时遇到了一些问题。它们都在 KeyboardInterrupt
上取消,但我注意到在那之后运行时需要恢复出厂设置,因为它不知何故卡住了。在 Linux 控制台中检查 ps aux
列出了一个进程 [ffmpeg] <defunct>
,不知何故它仍然是 运行 或者至少阻止了一些看起来像的资源。
然后我做了一些研究,发现了一些类似的帖子,询问有关如何正确终止子进程的问题 (1, , 3)。基于这些帖子,我通常得出结论,使用 subprocess.Popen(..)
变体在处理子流程时显然提供了更大的灵活性:定义不同的 stdout
过程或对不同的 returncode
等做出反应。但是我仍然不确定上面使用 !
作为前缀的第一个命令到底在做什么。
使用第一个命令要容易得多,并且需要更少的代码来启动这个过程。假设我不需要很多逻辑来处理流程,这将是执行类似 ffmpeg
的好方法 - 如果我能够按预期终止它。即使按照使用第二条命令的其他帖子的答案,我也从未达到可以在启动后完全终止进程的地步(即使使用 shell=False
、process.kill()
或 process.wait()
等。 ).这让我很沮丧,因为每次重新启动和重新初始化 Colab 实例本身都可能需要几分钟。
所以,最后,我想更笼统地了解区别是什么,并希望有人能启发我。谢谢!
!
命令由笔记本执行(或更具体地说,由 ipython
解释器执行),并且不是有效的 Python 命令。如果您编写的代码需要在 notebook 环境之外工作,则不能使用 !
命令。
正如您正确指出的那样,您无法与通过 !
启动的子流程进行交互;因此它也没有显式 subprocess
调用灵活,尽管在这方面类似于 subprocess.call
就像文档中提到的那样,除非您特别需要它提供的详细灵活性,否则您通常应该避免裸露的 subprocess.Popen
,代价是必须复制 [=18= 的 higher-level 功能]等。已经实施。 运行 命令并等待它完成的代码很简单
subprocess.check_call(['ffmpeg', ... ])
具有用于捕获其输出的变体 (check_output
) 和更现代的 run
,它可以轻松替换所有三个遗留 high-level 调用,尽管增加了一些冗长。
我已经使用 Google Colab 几个星期了,我一直想知道以下两个命令之间的区别(例如):
!ffmpeg ...
subprocess.Popen(['ffmpeg', ...
我想知道,因为我 运行 在启动上述任一命令然后尝试中途停止执行时遇到了一些问题。它们都在 KeyboardInterrupt
上取消,但我注意到在那之后运行时需要恢复出厂设置,因为它不知何故卡住了。在 Linux 控制台中检查 ps aux
列出了一个进程 [ffmpeg] <defunct>
,不知何故它仍然是 运行 或者至少阻止了一些看起来像的资源。
然后我做了一些研究,发现了一些类似的帖子,询问有关如何正确终止子进程的问题 (1, subprocess.Popen(..)
变体在处理子流程时显然提供了更大的灵活性:定义不同的 stdout
过程或对不同的 returncode
等做出反应。但是我仍然不确定上面使用 !
作为前缀的第一个命令到底在做什么。
使用第一个命令要容易得多,并且需要更少的代码来启动这个过程。假设我不需要很多逻辑来处理流程,这将是执行类似 ffmpeg
的好方法 - 如果我能够按预期终止它。即使按照使用第二条命令的其他帖子的答案,我也从未达到可以在启动后完全终止进程的地步(即使使用 shell=False
、process.kill()
或 process.wait()
等。 ).这让我很沮丧,因为每次重新启动和重新初始化 Colab 实例本身都可能需要几分钟。
所以,最后,我想更笼统地了解区别是什么,并希望有人能启发我。谢谢!
!
命令由笔记本执行(或更具体地说,由 ipython
解释器执行),并且不是有效的 Python 命令。如果您编写的代码需要在 notebook 环境之外工作,则不能使用 !
命令。
正如您正确指出的那样,您无法与通过 !
启动的子流程进行交互;因此它也没有显式 subprocess
调用灵活,尽管在这方面类似于 subprocess.call
就像文档中提到的那样,除非您特别需要它提供的详细灵活性,否则您通常应该避免裸露的 subprocess.Popen
,代价是必须复制 [=18= 的 higher-level 功能]等。已经实施。 运行 命令并等待它完成的代码很简单
subprocess.check_call(['ffmpeg', ... ])
具有用于捕获其输出的变体 (check_output
) 和更现代的 run
,它可以轻松替换所有三个遗留 high-level 调用,尽管增加了一些冗长。