知道子流程是否没有被打印到标准输出卡住



我有运行的子流程:

proc = subprocess.Popen("python -u my_script.py", shell=True)

my_script.py应该定期打印到stdout,而我有其他非相关的进程在监听这个输出,所以我不能将输出更改为打印到其他地方。

我想确保这个过程真的是定期打印的,不会陷入一些循环。等等,我有办法检查stdout是否被写入了一段时间吗?

还有其他实现这一目标的选择吗?

编辑

我正在使用windows

您可以使用mkfifo创建一个命名管道,并使用tee将脚本的数据输出到侦听它的进程和管道。

mkfifo blarg
my_script.py | tee blarg | your_greedy_data_processing_instance
tail -f blarg

您可以使用任意复杂的脚本来研究输出和生成它的进程的状态(计时器、pid检查(,而不是tail

/dev/stdout的访问时间和修改时间似乎定期更新。但是,请注意,对于检查/dev/stdout的进程,/dev/stdout将始终是一个软链接——呃,我的意思是符号链接——到stdout的文件句柄。即/dev/stdout链接到/proc/self/fd/1

因此,您似乎可以检查流程的第一个文件描述符,看看它的修改时间是否发生了变化,例如:

$ stat -c %y -L /proc/10830/fd/1
2021-05-13 02:34:00.367857061

-L意味着作用于软链路的目标,而不是软链路本身;-c %y只是要求修改时间。这个Python脚本现在在我的系统上作为进程10830运行,它偶尔会更新修改时间(大约每8秒更新一次(:

>>> import time
>>> while True: time.sleep(1); print("still alive")
still alive
still alive
still alive
....

不过,你应该用谷歌搜索这个答案,以确保我看到的行为是可靠的,因为我以前从未读过任何关于它的文章。

或者,您可以(a(相信脚本是好的——当然,它会一直是好的(除非它正在捕捉异常并拒绝退出,即使它不能再做任何有用的事情,在这种情况下,您应该将其更改为以应有的方式死亡(,或者(b(设置一个守护进程来执行一些操作,比如向脚本发送信号,在这一点上,脚本可以向守护进程发送一个信号;我还活着"在我看来,确实没有理由这么做,但如何编写程序取决于你自己。

因此,假设您想继续执行此操作,下面是一个守护进程的琐碎示例,它将监视您想要确保的脚本不会陷入循环或其他什么:

import time
import signal
import os
import sys
# keep a timestamp of when we receive a response
response_timestamp = time.time()
# add code here to get the process ID of the other script
other_pid = 0
def sig_handler(signum, frame):
global response_timestamp
response_timestamp = time.time()
if __name__ == '__main__':
# make sure that when we receive SIGBREAK, sig_handler() gets called
signal.signal(signal.SIGBREAK, sig_handler)
while True:
# send SIGBREAK to "other_pid"
os.kill(other_pid, signal.SIGBREAK)
time.sleep(15)

if time.time() - 20 > response_timestamp:
print("the other process is frozen")
sys.exit(os.EX_SOFTWARE)

然后将其添加到正在监视的另一个脚本中:

import signal
import os
# add code here to get the process ID
other_pid = 0
def sig_handler(signum, frame):
os.kill(other_pid, signal.SIGBREAK)
...
...
(rest of your script)

现在要意识到,这唯一能做的就是确保这个过程没有完全冻结。遗憾的是,Windows在信号方面没有太多选择:SIGBREAK是我见过的最好的一个,但请注意,它是当你按下CTRL+C来中断程序时进程接收到的信号(所以,如果你在运行Python程序的窗口中手动按下CTRL+C,它不会杀死它,只会让它调用sig_handler()(。

如果我没有通知您,即使这可能会很好地工作,在信号处理程序函数中执行几乎任何操作都是不安全的,那我也是失职的。这是一种糟糕的状态,可能会出乎意料地对你产生影响,但在实践中,这是非常安全的。

最新更新