如何终止某一线程中的 subprocess.Popen 以及非阻塞读取多个终端输出

2022-04-27 09:55:26 +08:00
 kayseen

需求是使用 subprocess 执行一个耗时命令,对终端的输出进行非阻塞的实时监控,当终端输出 error 信息时,关闭 Popen ,或者执行一段时间后自动关闭 Popen 。因为同时需要实时来监控多个终端输出,需要非阻塞。我依次使用了以下两种方法:

1 、 最初的实现为使用 asyncio 创建一个 loop 并且 run_forever() ,然后将读取 Popen 输出的阻塞方法( While Popen is None )注册到该 loop 上运行,读取 stdout 输出,如果没有检测到 error 信息,就 asyncio.sleep(0.01);后来我发现当存在多个 Popen 的时候,sleep 切换会导致有的终端输出读取丢失,并不能实时读取到,所以我采用第二种方法;

2 、 第二次实现是给每个 Popen 创建一个线程,使用线程的 daemon start 来实时监控,资源消耗会比 1 大但是目前还没有遇到读取实时监控的问题。

然后又有一个需求,如果用户想要中途终止该进行监控的 subprocess 的 Popen ,该如何中途停止该 Popen 呢?

另求:各路大神有没有比上述方案 1 和方案 2 中更适合的实现非阻塞实时读取输出的方案?

2168 次点击
所在节点    Python
8 条回复
ysc3839
2022-04-27 10:37:45 +08:00
我不了解 Python 。但是异步框架一般有读 fd 的功能吧?同时读所有管道对应的 fd 就好了。
julyclyde
2022-04-27 11:01:24 +08:00
不能实时还是不能读到?
LeeReamond
2022-04-27 11:10:26 +08:00
看了一下以前自己的实现,subprocess.Popen 是同步代码,肯定是不在事件循环的线程里执行的,创建子进程后用 process.stdout.fileno()拿到 stdout ,然后用 selectors.DefualtSelector 挂上,印象里这个 default 在 linux 下是会自动用 epoll ,推流用 call_soon_threadsafe 就推回事件循环了。关闭子进程用的是三方库 psutil ,selector 挂起无法自动关闭,解决方法是加个 timeout ,最慢 10 秒内关闭。
kayseen
2022-04-27 11:53:49 +08:00
@ysc3839 我曾经试过通过管道的 fd 来读取,但是也会因为 while Popen is None 阻塞线程,也有可能是我的使用方式不对
kayseen
2022-04-27 11:58:49 +08:00
@julyclyde 感谢回复。这是针对使用 asyncio 的 loop 实现的问题,我曾经复现过,是因为开启多个 popen 的时候,通过 asyncio.sleep 来切换读取其他的 popen ,如果一个 popen 此时输出了 error ,然后自动关闭了 popen ,因为 loop 此时切换到了其他的 popen 读取,就会丢失从 error 到关闭的范围内的输出
kayseen
2022-04-27 12:01:54 +08:00
@LeeReamond 感谢回复,思考了好一会,感觉思路挺清晰,大多是没有接触过的东西,要好好消化一会儿 qaq 。。。
wwqgtxx
2022-04-27 13:36:10 +08:00
asyncio 本来不就有对 popen 的支持么
https://docs.python.org/3/library/asyncio-subprocess.html
https://docs.python.org/3/library/asyncio-eventloop.html#running-subprocesses
多开几个 task 去用你的第二次实现的思路不就得了
lolizeppelin
2022-04-27 13:56:13 +08:00
linux 下用 fork exec 加 select 管道去折腾

折腾熟了 subprocess 什么回事自然就知道了

协程的话 eventlet 里有 GreenPile ,asyncio 里应该也有类似封装

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/849498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX