356

我正在尝试将 shell 脚本移植到更具可读性的 python 版本。原始的 shell 脚本使用“&”在后台启动多个进程(实用程序、监视器等)。我怎样才能在python中达到同样的效果?当 python 脚本完成时,我希望这些进程不会消失。我确信它以某种方式与守护进程的概念有关,但我找不到如何轻松地做到这一点。

4

9 回答 9

458

虽然jkp的解决方案有效,但更新的做事方式(以及文档推荐的方式)是使用该subprocess模块。对于简单的命令,它是等价的,但如果你想做一些复杂的事情,它提供了更多的选项。

您的案例示例:

import subprocess
subprocess.Popen(["rm","-r","some.file"])

这将rm -r some.file在后台运行。请注意,调用.communicate()从返回的对象Popen将阻塞,直到它完成,所以如果您希望它在后台运行,请不要这样做:

import subprocess
ls_output=subprocess.Popen(["sleep", "30"])
ls_output.communicate()  # Will block for 30 seconds

请参阅此处的文档。

另外,需要澄清一点:您在这里使用的“背景”纯粹是一个外壳概念;从技术上讲,您的意思是您希望在等待它完成时生成一个进程而不会阻塞。但是,我在这里使用“背景”来指代类似于 shell 背景的行为。

于 2011-08-28T21:47:04.450 回答
99

注意:这个答案比 2009 年发布时的更新要少。subprocess现在建议在文档中使用其他答案中显示的模块

(请注意,子进程模块提供了更强大的工具来生成新进程并检索其结果;使用该模块比使用这些函数更可取。)


如果你希望你的进程在后台启动,你可以使用system()和调用它,就像你的 shell 脚本一样,或者你可以spawn

import os
os.spawnl(os.P_DETACH, 'some_long_running_command')

(或者,您可以尝试使用不太便携的os.P_NOWAIT标志)。

请参阅此处的文档

于 2009-07-28T19:05:23.843 回答
54

您可能想要“如何在 Python 中调用外部命令”的答案。

最简单的方法是使用os.system函数,例如:

import os
os.system("some_command &")

基本上,您传递给system函数的任何内容都将被执行,就像您在脚本中将其传递给 shell 一样。

于 2009-07-28T19:02:59.293 回答
37

我在这里找到了这个:

longtask.py在 Windows (win xp) 上,父进程在完成其工作之前不会完成。这不是您在 CGI 脚本中想要的。该问题并非特定于 Python,在 PHP 社区中的问题是相同的。

解决方法是在win API中将DETACHED_PROCESS Process Creation Flag传递给底层函数。CreateProcess如果你碰巧安装了 pywin32,你可以从 win32process 模块导入标志,否则你应该自己定义它:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid
于 2012-11-27T21:19:09.710 回答
33

subprocess.Popen()与参数一起使用close_fds=True,这将允许生成的子进程与 Python 进程本身分离,并在 Python 退出后继续运行。

https://gist.github.com/yinjimmy/d6ad0742d03d54518e9f

import os, time, sys, subprocess

if len(sys.argv) == 2:
    time.sleep(5)
    print 'track end'
    if sys.platform == 'darwin':
        subprocess.Popen(['say', 'hello'])
else:
    print 'main begin'
    subprocess.Popen(['python', os.path.realpath(__file__), '0'], close_fds=True)
    print 'main end'
于 2015-12-25T01:47:55.303 回答
14

捕获输出并在后台运行threading

this answer中所述,如果您使用捕获输出stdout=然后尝试捕获read(),则该过程会阻塞。

但是,在某些情况下您需要这样做。例如,我想启动两个通过它们之间的端口进行通信的进程,并将它们的标准输出保存到日志文件和标准输出中。

threading模块允许我们这样做。

首先,看看如何在这个问题中单独执行输出重定向部分:Python Popen: Write to stdout AND log file 同时

然后:

主文件

#!/usr/bin/env python3

import os
import subprocess
import sys
import threading

def output_reader(proc, file):
    while True:
        byte = proc.stdout.read(1)
        if byte:
            sys.stdout.buffer.write(byte)
            sys.stdout.flush()
            file.buffer.write(byte)
        else:
            break

with subprocess.Popen(['./sleep.py', '0'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc1, \
     subprocess.Popen(['./sleep.py', '10'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc2, \
     open('log1.log', 'w') as file1, \
     open('log2.log', 'w') as file2:
    t1 = threading.Thread(target=output_reader, args=(proc1, file1))
    t2 = threading.Thread(target=output_reader, args=(proc2, file2))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

睡眠.py

#!/usr/bin/env python3

import sys
import time

for i in range(4):
    print(i + int(sys.argv[1]))
    sys.stdout.flush()
    time.sleep(0.5)

运行后:

./main.py

stdout 每 0.5 秒更新一次,每两行包含:

0
10
1
11
2
12
3
13

每个日志文件都包含给定进程的相应日志。

灵感来自:https ://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

在 Ubuntu 18.04、Python 3.6.7 上测试。

于 2018-12-12T21:48:55.903 回答
12

您可能想开始研究用于分叉不同线程的 os 模块(通过打开交互式会话并发出帮助(os))。相关函数是 fork 和任何 exec 函数。为了让您了解如何开始,请将类似这样的内容放在执行 fork 的函数中(该函数需要将列表或元组 'args' 作为包含程序名称及其参数的参数;您可能还想要为新线程定义标准输入、输出和错误):

try:
    pid = os.fork()
except OSError, e:
    ## some debug output
    sys.exit(1)
if pid == 0:
    ## eventually use os.putenv(..) to set environment variables
    ## os.execv strips of args[0] for the arguments
    os.execv(args[0], args)
于 2009-07-28T19:12:06.280 回答
0

您可以使用

import os
pid = os.fork()
if pid == 0:
    Continue to other code ...

这将使python进程在后台运行。

于 2021-03-04T16:14:44.853 回答
0

我还没有尝试过,但你不能使用 .pyw 文件而不是 .py 文件吗?pyw 文件没有控制台,所以理论上它不应该像后台进程一样出现和工作

于 2022-02-10T02:16:26.667 回答