从Python生成进程

14 投票
2 回答
39908 浏览
提问于 2025-04-15 12:08

我正在从一个网页应用程序启动一个运行很长时间的脚本,代码如下:

os.spawnle(os.P_NOWAIT, "../bin/producenotify.py", "producenotify.py", "xx",os.environ)

这个脚本成功启动并在运行,但在它完成之前,我无法释放网页应用程序使用的端口,换句话说,我无法重启这个网页应用程序。我该如何启动一个进程,让它完全独立于网页应用程序呢?

这是在Linux操作系统上进行的。

2 个回答

12

你可以使用 multiprocessing 这个库来创建多个进程。下面是一个简单的例子:

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
26

正如@mark所说,这是一个Linux系统,这个脚本可以很容易地让自己完全独立,也就是变成一个守护进程,可以参考这个教程。(你也可以在父进程中先使用os.fork,然后再用os.exec...来启动子进程)。

编辑:为了澄清一些细节,关于@mark对我回答的评论:根据这个教程,"守护进程化"一个进程并不需要超级用户权限,也不需要改变当前工作目录(虽然教程中的代码确实做了这些,但这并不是关键部分,关键在于fork_exitsetsid的调用顺序)。各种不以e结尾的os.exec...变体使用的是父进程的环境,所以这一部分也很简单——可以查看Python在线文档

关于其他评论和回答中的建议:我认为subprocessmultiprocessing本身并不会让子进程变成守护进程,这似乎是@mark所需要的;脚本可以自己做到这一点,但因为某些代码必须执行forksetsid,所以我觉得把所有的创建进程的操作都放在低级别的地方会更整洁,而不是在操作过程中混合高层和低层代码。

这里是上面网址中教程的一个大幅简化版本,适合在父进程中调用以生成一个守护进程子进程——这样,代码也可以用来执行非Python的可执行文件。按照给出的代码,应该能满足@mark所说的需求,当然也可以有很多种调整方式——我强烈建议阅读原始教程及其评论和讨论,还有它推荐的书籍,以获取更多信息。

import os
import sys

def spawnDaemon(path_to_executable, *args)
    """Spawn a completely detached subprocess (i.e., a daemon).

    E.g. for mark:
    spawnDaemon("../bin/producenotify.py", "producenotify.py", "xx")
    """
    # fork the first time (to make a non-session-leader child process)
    try:
        pid = os.fork()
    except OSError, e:
        raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
    if pid != 0:
        # parent (calling) process is all done
        return

    # detach from controlling terminal (to make child a session-leader)
    os.setsid()
    try:
        pid = os.fork()
    except OSError, e:
        raise RuntimeError("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
        raise Exception, "%s [%d]" % (e.strerror, e.errno)
    if pid != 0:
        # child process is all done
        os._exit(0)

    # grandchild process now non-session-leader, detached from parent
    # grandchild process must now close all open files
    try:
        maxfd = os.sysconf("SC_OPEN_MAX")
    except (AttributeError, ValueError):
        maxfd = 1024

    for fd in range(maxfd):
        try:
           os.close(fd)
        except OSError: # ERROR, fd wasn't open to begin with (ignored)
           pass

    # redirect stdin, stdout and stderr to /dev/null
    os.open(os.devnull, os.O_RDWR)  # standard input (0)
    os.dup2(0, 1)
    os.dup2(0, 2)

    # and finally let's execute the executable for the daemon!
    try:
      os.execv(path_to_executable, args)
    except Exception, e:
      # oops, we're cut off from the world, let's just give up
      os._exit(255)

撰写回答