如何在Windows上分离Python子进程(不使用setsid)?

4

我正在将一些在Posix系统上运行良好的进程代码迁移到Windows操作系统。 简单来说:启动子进程并立即分离的代码将无法工作,因为Windows上不支持 setsid() 函数。

import os, subprocess, sys
p = subprocess.Popen([sys.executable, '-c', "print 'hello'"], preexec_fn=os.setsid)

我可以去掉setsid的使用,但父进程结束时子进程也将结束。
我的问题是如何在Windows上实现与setsid相同的效果,以使子进程的生命周期独立于父进程? 如果存在这样的Python包,我愿意使用它。例如,我已经在使用psutil,但我没有看到任何可以帮助我的东西。

在Windows中,子进程的生命周期独立于父进程,它不会“附加”到父进程。 - RbMm
1个回答

4

然而,正如eryksun在这里的评论中指出的那样,关闭控制台窗口将导致子进程终止。我在Windows上还遇到了Waitress和Popen的一些稳定性问题,我通过添加以下代码段解决了这些问题,该代码段设置了一些进程创建标志并使用close_fds

if 'nt' == os.name:
     flags = 0
     flags |= 0x00000008  # DETACHED_PROCESS
     flags |= 0x00000200  # CREATE_NEW_PROCESS_GROUP
     flags |= 0x08000000  # CREATE_NO_WINDOW

     pkwargs = {
         'close_fds': True,  # close stdin/stdout/stderr on child
         'creationflags': flags,
     }

 p = subprocess.Popen([sys.executable, '-c', cmd], **pkwargs)

1
是的和不是的。默认情况下,进程继承其父进程的进程组。组ID用于向属于组的进程发送控制台CTRL_C_EVENTCTRL_BREAK_EVENT。此外,当关闭控制台时,所有附加到它的进程都会收到CTRL_CLOSE_EVENT警告,并在5秒后被强制终止。由于一个进程被标记为控制台窗口的有效所有者(通常是分配进程),因此通过taskill.exe或任务管理器杀死所有者会向控制台窗口发送WM_CLOSE,并终止每个附加到控制台的进程。 - Eryk Sun
1
要获取一个新的控制台,请使用创建标志CREATE_NEW_CONSOLECREATE_NO_WINDOW(即没有窗口的新控制台)。要跳过附加到任何控制台,请使用DETACHED_PROCESS。要创建一个新组,请使用CREATE_NEW_PROCESS_GROUP。对于后者,默认情况下,如果附加到控制台,则在子进程中将禁用Ctrl+C;可以通过SetConsoleCtrlHandler手动启用。 - Eryk Sun
运行得非常好,(有点)我使用了微妙的变化 p = subprocess.Popen([sys.executable, cmd], **pkwargs)。在Python 3.6.x上也可以工作。 - Supun De Silva
如果脚本在SSH中运行,您可能还需要使用CREATE_BREAKAWAY_FROM_JOB。它的作用类似于Linux中的nohup - Cruise Liu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接