12

我的 python 脚本可以生成一个无限期运行的进程吗?

我对python不太熟悉,也不熟悉产卵恶魔,所以我想出了这个:

si = subprocess.STARTUPINFO()
si.dwFlags = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.CREATE_NEW_CONSOLE
subprocess.Popen(executable, close_fds = True, startupinfo = si)

该进程继续运行通过 python.exe,但在我关闭 cmd 窗口后立即关闭。

4

3 回答 3

20

使用答案Janne Karila 指出,这是您如何运行一个在其父级死亡时不会死亡的进程,而无需使用该win32process模块。

DETACHED_PROCESS = 8
subprocess.Popen(executable, creationflags=DETACHED_PROCESS, close_fds=True)

DETACHED_PROCESS是传递给底层CreateProcess函数的进程创建标志。

于 2012-10-12T07:37:39.577 回答
18

这个问题是 3 年前提出的,虽然答案的基本细节没有改变,但鉴于它在“Windows Python 守护进程”搜索中的普遍性,我认为添加一些讨论可能有助于未来谷歌的到来。

这个问题实际上有两个部分:

  1. Python 脚本能否生成一个可以无限期运行的独立进程?
  2. Python 脚本可以像 Windows 系统上的 Unix 守护进程一样工作吗?

第一个答案是肯定的。正如已经指出的那样;使用关键字就足够subprocess.Popen了:creationflags=subprocess.CREATE_NEW_PROCESS_GROUP

import subprocess

independent_process = subprocess.Popen(
    'python /path/to/file.py',
    creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)

请注意,至少根据我的经验,CREATE_NEW_CONSOLE这里没有必要。

话虽如此,这种策略的行为与您对 Unix 守护程序的期望并不完全相同。什么是行为良好的 Unix 守护进程在别处有更好的解释,但总结一下:

  1. 关闭打开的文件描述符(通常是全部,但某些应用程序可能需要保护某些描述符不被关闭)
  2. 将进程的工作目录更改为合适的位置,以防止出现“Directory Busy”错误
  3. 更改文件访问创建掩码(os.umask在 Python 世界中)
  4. 将应用程序移至后台并使其与启动进程分离
  5. 完全脱离终端,包括重定向、、、STDINSTDOUTSTDERR不同的流(经常DEVNULL),防止重新获取控制终端
  6. 处理信号,特别是SIGTERM.

实际情况是,Windows 作为一个操作系统,确实不支持守护进程的概念:从终端启动(或在任何其他交互式上下文中,包括从资源管理器启动等)启动的应用程序将继续运行具有可见窗口,除非控制应用程序(在此示例中为 Python)包含无窗口 GUI。此外,Windows 信号处理严重不足,并且尝试将信号发送到独立的Python 进程(与无法在终端关闭后幸存的子进程相反)几乎总是会导致该 Python 进程立即退出而没有任何清理(没有finally:, 不atexit, 不__del__, 等等)。

将您的应用程序滚动到 Windows 服务中,虽然在许多情况下是一种可行的替代方案,但也不太适合。使用pythonw.exe(所有最近的 Windows Python 二进制文件附带的无窗口 Python 版本)也是如此。特别是,它们无法改善信号处理的情况,并且它们无法轻松地从终端启动应用程序并在启动期间与之交互(例如,向脚本传递动态启动参数,例如密码、文件路径等),之前“恶魔化”。此外,Windows 服务需要安装,尽管当您第一次调用“守护程序”时可以在运行时快速完成,但它会修改用户的系​​统(注册表等),如果您来自一个 Unix 世界。

鉴于此,我认为启动pythonw.exe子进程 usingsubprocess.CREATE_NEW_PROCESS_GROUP可能是 Python 进程模拟传统 Unix 守护进程最接近的 Windows 等价物。然而,这仍然给您带来了信号处理和启动通信的额外挑战(更不用说让您的代码依赖于平台,这总是令人沮丧)。

话虽如此,对于将来遇到此问题的任何人,我推出了一个名为daemoniker的库,它包装了正确的 Unix 守护进程上述策略。它还实现了信号处理(适用于 Unix 和 Windows 系统),并允许您使用 pickle 将对象传递给“守护进程”进程。最重要的是,它有一个跨平台的 API

from daemoniker import Daemonizer

with Daemonizer() as (is_setup, daemonizer):
    if is_setup:
        # This code is run before daemonization.
        do_things_here()

    # We need to explicitly pass resources to the daemon; other variables
    # may not be correct
    is_parent, my_arg1, my_arg2 = daemonizer(
        path_to_pid_file,
        my_arg1,
        my_arg2
    )

    if is_parent:
        # Run code in the parent after daemonization
        parent_only_code()

# We are now daemonized, and the parent just exited.
code_continues_here()
于 2016-09-27T02:24:20.737 回答
7

为此,您可以守护您的 python 进程,或者当您使用 Windows 环境时,您希望将其作为 Windows 服务运行。

你知道我讨厌只发布网络链接:

但根据您的要求了解更多信息:

一种实现 Windows 服务的简单方法阅读所有评论它将解决任何疑问

如果你真的想了解更多

先读这个

什么是守护进程或创建守护进程 python 方式

更新: 子流程不是实现这种事情的正确方法

于 2012-10-11T16:44:34.537 回答