¿Cómo iniciar un proceso en segundo plano en Python?

Estoy tratando de portar un script de shell a la versión de Python mucho más legible. El script de shell original inicia varios procesos (utilidades, monitores, etc.) en segundo plano con “&”. ¿Cómo puedo lograr el mismo efecto en python? Me gustaría que estos procesos no mueran cuando se completen los scripts de python. Estoy seguro de que está relacionado con el concepto de demonio de alguna manera, pero no pude encontrar cómo hacerlo fácilmente.

Nota : esta respuesta es menos actual de lo que era cuando se publicó en 2009. Ahora se recomienda usar el módulo de subprocess se muestra en otras respuestas en la documentación.

(Tenga en cuenta que el módulo de subproceso proporciona instalaciones más potentes para generar nuevos procesos y recuperar sus resultados; es preferible utilizar ese módulo que usar estas funciones).


Si desea que su proceso se inicie en segundo plano, puede usar system() y llamarlo de la misma forma que lo hizo su script de shell, o puede spawn :

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

(O, como alternativa, puede probar el indicador os.P_NOWAIT menos portátil).

Vea la documentación aquí .

Si bien la solución de jkp funciona, la forma más nueva de hacer las cosas (y la forma en que la documentación recomienda) es utilizar el módulo de subprocess . Para comandos simples es su equivalente, pero ofrece más opciones si desea hacer algo complicado.

Ejemplo para su caso:

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

Esto debería ejecutar rm -r somefile en segundo plano. Pero tenga cuidado: subprocess.Popen() solo ejecuta un proceso en segundo plano si nada en el script de python depende de la salida del comando que se ejecuta:

Por ejemplo, el siguiente comando no se ejecutará en segundo plano:

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

Vea la documentación aquí .

También, un punto de aclaración: “Fondo” puramente un concepto de shell: lo que probablemente desee es generar un nuevo proceso. He usado “fondo” aquí para referirme a un comportamiento similar a un fondo de shell, pero no confunda esto con el proceso que realmente está en segundo plano.

Probablemente desee la respuesta a “Cómo llamar un comando externo en Python” .

El enfoque más simple es usar la función os.system , por ejemplo:

 import os os.system("some_command &") 

Básicamente, todo lo que pase a la función del system se ejecutará de la misma manera que si lo hubiera pasado al shell en un script.

Encontré esto aquí :

En windows (win xp), el proceso padre no terminará hasta que longtask.py haya terminado su trabajo. No es lo que quieres en CGI-script. El problema no es específico de Python, en la comunidad de PHP los problemas son los mismos.

La solución es pasar el indicador de creación de proceso DETACHED_PROCESS a la función CreateProcess subyacente en la API win. Si tiene instalado pywin32, puede importar el indicador desde el módulo win32process, de lo contrario, debería definirlo usted mismo:

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

Use subprocess.Popen() con el parámetro close_fds=True , que permitirá que el subproceso generado se separe del propio proceso de Python y continúe ejecutándose incluso después de que Python salga.

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' 

Probablemente desee comenzar a investigar el módulo os para forzar diferentes hilos (abriendo una sesión interactiva y emitiendo ayuda (os)). Las funciones relevantes son fork y cualquiera de las ejecutivas. Para darle una idea sobre cómo comenzar, ponga algo como esto en una función que realice la bifurcación (la función necesita tomar una lista o tupla ‘args’ como argumento que contiene el nombre del progtwig y sus parámetros; también puede desear para definir stdin, out y errar para el nuevo hilo):

 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) 

Ambos capturan la salida y se ejecutan en segundo plano con threading

Como se mencionó en esta respuesta , si captura la salida con stdout= y luego intenta read() , entonces el proceso se bloquea.

Sin embargo, hay casos en los que necesita esto. Por ejemplo, quería iniciar dos procesos que hablen sobre un puerto entre ellos y guardar su salida estándar en un archivo de registro y salida estándar.

El módulo de threading nos permite hacer eso.

Primero, eche un vistazo a cómo hacer la parte de redirección de salida solo en esta pregunta: Python Popen: escriba en el archivo de registro de la salida estándar Y simultáneamente

Entonces:

main.py

 #!/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() 

dormir.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) 

Despues de correr:

 ./main.py 

stdout se actualiza cada 0.5 segundos por cada dos líneas para contener:

 0 10 1 11 2 12 3 13 

y cada archivo de registro contiene el registro respectivo para un proceso dado.

Inspirado por: https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

Probado en Ubuntu 18.04, Python 3.6.7.