简体   繁体   English

使用subprocess.Popen恢复进程?

[英]Recover process with subprocess.Popen?

I have a python program that uses subprocess.Popen to launch another process (python process or whatever), and after launching it I save the child's PID to a file. 我有一个使用subprocess.Popen来启动另一个进程(python进程或其他进程)的python程序,启动它后,我将孩子的PID保存到文件中。 Let's suppose that suddenly the parent process dies (because of an exception or whatever). 让我们假设父进程突然死亡(由于异常或其他原因)。 Is there any way to access again to the object returned by Popen ? 有什么办法可以再次访问Popen返回的对象?

I mean, the basic idea is to read the file at first, and if it exists and it has a PID written on it, then access to that process someway, in order to know the return code or whatever. 我的意思是,基本思想是首先读取文件,如果文件存在并且上面写有PID,则以某种方式访问​​该过程,以便了解返回码或其他内容。 If there isn't a PID, then launch the process with Popen . 如果没有PID,请使用Popen启动该过程。

Thanks a lot!! 非常感谢!!

The Popen object is effectively just a wrapper for the child processes PID, stdin, stdout, and stderr, plus some convenience functions for using those. Popen对象实际上只是子进程PID,stdin,stdout和stderr的包装,以及使用它们的一些便利功能。

So the question is why do you need access to the Popen object? 所以问题是为什么您需要访问Popen对象? Do you want to communicate with the child, terminate it, or check whether it's still running? 您要与孩子沟通,终止它还是检查它是否仍在运行?

In any case there is no way reacquire a Popen object for an already running process. 无论如何,都无法为已经运行的进程重新获取Popen对象。

The proper way to approach this is to launch the child as a daemon, like Tobu suggested. 正确的方法是像Tobu建议的那样,将孩子作为守护进程启动。 Part of the procedure for daemonising a process is to close stdin and stdout, so you cannot use those to talk to the child process. 守护进程的部分过程是关闭stdin和stdout,因此您不能使用它们与子进程进行对话。 Instead most daemons use either pipes or sockets to allow clients to connect to them and to send them messages. 相反,大多数守护程序使用管道或套接字来允许客户端连接到它们并向他们发送消息。

The easiest way to talk to the child is to open a named pipe from the child process at eg /etc/my_pipe, open that named pipe from the parent / controlling process, and write / read to / from it. 与子进程进行对话的最简单方法是从子进程中的/ etc / my_pipe中打开一个命名管道,从父进程/控制进程中打开该命名管道,然后从中进行写入/读取。

After a quick look at python-daemon it seems to me that python-daemon will help you daemonise your child process, which is tricky to get right, but it doesn't help you with the messaging side of things. 在快速浏览python-daemon之后,在我看来python-daemon可以帮助您守护子进程,这很棘手,但是在消息传递方面并没有帮助。

But like I said, I think you need to tell us why you need a Popen object for the child process before we can help you any further. 但是就像我说的那样,我认为您需要告诉我们为什么子流程需要一个Popen对象,然后我们才能进一步帮助您。

If a process dies, all its open file handles are closed. 如果进程死亡,则其所有打开的文件句柄都将关闭。 This includes any unnamed pipes created by popen() . 这包括popen()创建的所有未命名管道。 So, no, there's no way to recover a Popen object from just a PID. 因此,不行,没有办法仅从PID恢复Popen对象。 The OS won't even consider your new process the parent, so you won't even get SIGCHLD signals (though waitpid() might still work). 操作系统甚至不会将新进程视为父进程,因此您甚至都不会收到SIGCHLD信号(尽管waitpid()可能仍然有效)。

I'm not sure if the child is guaranteed to survive, either, since a write to a pipe with no reader (namely, the redirected stdout of the child) should kill the child with a SIGPIPE . 我不确定孩子是否也可以生存,因为对没有读取器的管道进行写操作(即,该孩子的重定向stdout )应使用SIGPIPE杀死该孩子。

If you want your parent process to pick up where the child left off, you need to spawn the child to write to a file, usually in /tmp or /var/log , and have it record its PID like you are now (the usual location is /var/run ). 如果要让父进程在子进程停止的地方继续工作,则需要生成该子进程以写入文件,通常是在/tmp/var/log ,并像现在一样记录它的PID(通常位置是/var/run )。 (Having it write to a named pipe risks getting it killed with SIGPIPE as above.) If you suffix your filename with the PID, then it becomes easy for the manager process to figure out which file belongs to which daemon. (将其写入命名管道可能会导致如上所述被SIGPIPE杀死。)如果在文件名后加上PID,则管理器进程很容易找出哪个文件属于哪个守护程序。

Looks like you're trying to write a daemon, and it needs pidfile support. 看起来您正在尝试编写守护程序,它需要pidfile支持。 You can't go wrong with python-daemon . python-daemon不会出错。

For example: 例如:

import daemon
import lockfile
import os

with daemon.DaemonContext(pidfile=lockfile.FileLock('/var/run/spam.pid')):
    os.execl('/path/to/prog', args…)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM