如何在Python中启动后台进程?

时间:2021-06-03 19:17:02

I'm trying to port a shell script to the much more readable python version. The original shell script starts several processes (utilities, monitors, etc.) in the background with "&". How can I achieve the same effect in python? I'd like these processes not to die when the python scripts complete. I am sure it's related to the concept of a daemon somehow, but I couldn't find how to do this easily.

我正在尝试将shell脚本移植到可读性更好的python版本中。原始shell脚本使用“&”在后台启动几个进程(实用程序、监视器等)。如何在python中实现相同的效果?当python脚本完成时,我希望这些进程不会死亡。我确信它与守护进程的概念有关,但我找不到如何轻松地做到这一点。

6 个解决方案

#1


63  

Note: This answer is less current than it was when posted in 2009. Using the subprocess module shown in other answers is now recommended in the docs

注意:这个答案比2009年发布的时候要少。现在,在文档中推荐使用其他答案中所示的子过程模块

(Note that the subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using these functions.)

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


If you want your process to start in the background you can either use system() and call it in the same way your shell script did, or you can spawn it:

如果您希望进程在后台启动,您可以使用system()并以shell脚本的方式调用它,也可以生成它:

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

(or, alternatively, you may try the less portable os.P_NOWAIT flag).

(或者,你也可以试试不那么便携的操作系统。P_NOWAIT国旗)。

See the documentation here.

在这里看到的文档。

#2


277  

While jkp's solution works, the newer way of doing things (and the way the documentation recommends) is to use the subprocess module. For simple commands its equivalent, but it offers more options if you want to do something complicated.

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

Example for your case:

你的案子的示例:

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

This should run rm -r somefile in the background. But be wary: subprocess.Popen() only runs a process in the background if nothing in the python script depends on the output of the command being run:

这应该在后台运行rm -r文件。但是要注意:subprocess.Popen()只在后台运行一个进程,如果python脚本中没有任何内容依赖于正在运行的命令的输出:

For example, the following command will not run in the background:

例如,下面的命令不会在后台运行:

import subprocess
ls_output=subprocess.Popen(["ls", "-a"], stdout=subprocess.PIPE)

See the documentation here.

在这里看到的文档。

Also, a point of clarification: "Background" purely a shell concept: what you probably want is to spawn a new process. I've used "background" here to refer to shell-background-like behavior, but don't mistake this for the process actually being in the background.

另外,需要澄清的一点是:“Background”纯粹是shell概念:您可能希望生成一个新进程。我在这里使用了“background”来指代shell-background-like行为,但是不要把它误认为是后台的过程。

#3


28  

You probably want the answer to "How to call an external command in Python".

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

The simplest approach is to use the os.system function, e.g.:

最简单的方法是使用操作系统。系统功能,例如:

import os
os.system("some_command &")

Basically, whatever you pass to the system function will be executed the same as if you'd passed it to the shell in a script.

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

#4


20  

I found this here:

我发现在这里:

On windows (win xp), the parent process will not finish until the longtask.py has finished its work. It is not what you want in CGI-script. The problem is not specific to Python, in PHP community the problems are the same.

在windows (win xp)中,父进程直到长任务才会结束。py已经完成了工作。这不是您在CGI-script中想要的。问题不是针对Python的,在PHP社区中问题是相同的。

The solution is to pass DETACHED_PROCESS Process Creation Flag to the underlying CreateProcess function in win API. If you happen to have installed pywin32 you can import the flag from the win32process module, otherwise you should define it yourself:

解决方案是将DETACHED_PROCESS创建标志传递给win API中的底层CreateProcess函数。如果您恰好安装了pywin32,您可以从win32process模块中导入标志,否则您应该自己定义它:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

#5


13  

Use subprocess.Popen() with the close_fds=True parameter, which will allow the spawned subprocess to be detached from the Python process itself and continue running even after Python exits.

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

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

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'

#6


10  

You probably want to start investigating the os module for forking different threads (by opening an interactive session and issuing help(os)). The relevant functions are fork and any of the exec ones. To give you an idea on how to start, put something like this in a function that performs the fork (the function needs to take a list or tuple 'args' as an argument that contains the program's name and its parameters; you may also want to define stdin, out and err for the new thread):

您可能想要开始研究os模块来划分不同的线程(通过打开交互式会话并发出帮助(os)))。相关的函数是fork和任何exec函数。为了让您了解如何开始,在执行fork的函数中放置类似的东西(函数需要使用一个列表或元组“args”作为参数,其中包含程序的名称及其参数;您可能还想定义stdin、out和err作为新线程):

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)

#1


63  

Note: This answer is less current than it was when posted in 2009. Using the subprocess module shown in other answers is now recommended in the docs

注意:这个答案比2009年发布的时候要少。现在,在文档中推荐使用其他答案中所示的子过程模块

(Note that the subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using these functions.)

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


If you want your process to start in the background you can either use system() and call it in the same way your shell script did, or you can spawn it:

如果您希望进程在后台启动,您可以使用system()并以shell脚本的方式调用它,也可以生成它:

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

(or, alternatively, you may try the less portable os.P_NOWAIT flag).

(或者,你也可以试试不那么便携的操作系统。P_NOWAIT国旗)。

See the documentation here.

在这里看到的文档。

#2


277  

While jkp's solution works, the newer way of doing things (and the way the documentation recommends) is to use the subprocess module. For simple commands its equivalent, but it offers more options if you want to do something complicated.

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

Example for your case:

你的案子的示例:

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

This should run rm -r somefile in the background. But be wary: subprocess.Popen() only runs a process in the background if nothing in the python script depends on the output of the command being run:

这应该在后台运行rm -r文件。但是要注意:subprocess.Popen()只在后台运行一个进程,如果python脚本中没有任何内容依赖于正在运行的命令的输出:

For example, the following command will not run in the background:

例如,下面的命令不会在后台运行:

import subprocess
ls_output=subprocess.Popen(["ls", "-a"], stdout=subprocess.PIPE)

See the documentation here.

在这里看到的文档。

Also, a point of clarification: "Background" purely a shell concept: what you probably want is to spawn a new process. I've used "background" here to refer to shell-background-like behavior, but don't mistake this for the process actually being in the background.

另外,需要澄清的一点是:“Background”纯粹是shell概念:您可能希望生成一个新进程。我在这里使用了“background”来指代shell-background-like行为,但是不要把它误认为是后台的过程。

#3


28  

You probably want the answer to "How to call an external command in Python".

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

The simplest approach is to use the os.system function, e.g.:

最简单的方法是使用操作系统。系统功能,例如:

import os
os.system("some_command &")

Basically, whatever you pass to the system function will be executed the same as if you'd passed it to the shell in a script.

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

#4


20  

I found this here:

我发现在这里:

On windows (win xp), the parent process will not finish until the longtask.py has finished its work. It is not what you want in CGI-script. The problem is not specific to Python, in PHP community the problems are the same.

在windows (win xp)中,父进程直到长任务才会结束。py已经完成了工作。这不是您在CGI-script中想要的。问题不是针对Python的,在PHP社区中问题是相同的。

The solution is to pass DETACHED_PROCESS Process Creation Flag to the underlying CreateProcess function in win API. If you happen to have installed pywin32 you can import the flag from the win32process module, otherwise you should define it yourself:

解决方案是将DETACHED_PROCESS创建标志传递给win API中的底层CreateProcess函数。如果您恰好安装了pywin32,您可以从win32process模块中导入标志,否则您应该自己定义它:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

#5


13  

Use subprocess.Popen() with the close_fds=True parameter, which will allow the spawned subprocess to be detached from the Python process itself and continue running even after Python exits.

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

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

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'

#6


10  

You probably want to start investigating the os module for forking different threads (by opening an interactive session and issuing help(os)). The relevant functions are fork and any of the exec ones. To give you an idea on how to start, put something like this in a function that performs the fork (the function needs to take a list or tuple 'args' as an argument that contains the program's name and its parameters; you may also want to define stdin, out and err for the new thread):

您可能想要开始研究os模块来划分不同的线程(通过打开交互式会话并发出帮助(os)))。相关的函数是fork和任何exec函数。为了让您了解如何开始,在执行fork的函数中放置类似的东西(函数需要使用一个列表或元组“args”作为参数,其中包含程序的名称及其参数;您可能还想定义stdin、out和err作为新线程):

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)