2011-05-12 21 views
21

Un script de python imprime información en la pantalla y luego debe ir al fondo.Llevar el programa actual de Python al fondo

¿Cómo hacerlo desde el propio script?

+1

duplicados de http://stackoverflow.com/questions/1196074/starting-a-background-process-in-python – tmg

+2

@tmg: Eso no es un DUP. El enlace que publicó es cómo iniciar un nuevo proceso en segundo plano, no cómo hacer que el proceso actual pase al segundo plano después de algunas acciones. –

Respuesta

17

Actualización: Para daemonizar correctamente su proceso, use daemonize.

Respuesta original: Dado que el shell está esperando a que termine el proceso, el proceso principal debe finalizar. Puede utilizar os.fork() al tenedor de un proceso hijo y sys.exit() del proceso padre:

import os 
import sys 

if os.fork(): 
    sys.exit() 
# Child code goes here 
+0

Es posible que desee especificar "import sys" para que esto sea más fácil para los nuevos Pythoners – PSSGCSim

+1

@PSSGCSim Sí, eso fue un poco inconsistente. También actualicé la respuesta para incluir la forma más conveniente de crear un daemon de Python adecuado. –

22

copia del código relacionado Creating a daemon the Python way; por favor, lea los comentarios sobre por qué ese código está bastante pensado.

def createDaemon(): 
    """Detach a process from the controlling terminal and run it in the 
    background as a daemon. 
    """ 

    try: 
     # Fork a child process so the parent can exit. This returns control to 
     # the command-line or shell. It also guarantees that the child will not 
     # be a process group leader, since the child receives a new process ID 
     # and inherits the parent's process group ID. This step is required 
     # to insure that the next call to os.setsid is successful. 
     pid = os.fork() 
    except OSError, e: 
     raise Exception, "%s [%d]" % (e.strerror, e.errno) 

    if (pid == 0): # The first child. 
     # To become the session leader of this new session and the process group 
     # leader of the new process group, we call os.setsid(). The process is 
     # also guaranteed not to have a controlling terminal. 
     os.setsid() 

     # Is ignoring SIGHUP necessary? 
     # 
     # It's often suggested that the SIGHUP signal should be ignored before 
     # the second fork to avoid premature termination of the process. The 
     # reason is that when the first child terminates, all processes, e.g. 
     # the second child, in the orphaned group will be sent a SIGHUP. 
     # 
     # "However, as part of the session management system, there are exactly 
     # two cases where SIGHUP is sent on the death of a process: 
     # 
     # 1) When the process that dies is the session leader of a session that 
     #  is attached to a terminal device, SIGHUP is sent to all processes 
     #  in the foreground process group of that terminal device. 
     # 2) When the death of a process causes a process group to become 
     #  orphaned, and one or more processes in the orphaned group are 
     #  stopped, then SIGHUP and SIGCONT are sent to all members of the 
     #  orphaned group." [2] 
     # 
     # The first case can be ignored since the child is guaranteed not to have 
     # a controlling terminal. The second case isn't so easy to dismiss. 
     # The process group is orphaned when the first child terminates and 
     # POSIX.1 requires that every STOPPED process in an orphaned process 
     # group be sent a SIGHUP signal followed by a SIGCONT signal. Since the 
     # second child is not STOPPED though, we can safely forego ignoring the 
     # SIGHUP signal. In any case, there are no ill-effects if it is ignored. 
     # 
     # import signal   # Set handlers for asynchronous events. 
     # signal.signal(signal.SIGHUP, signal.SIG_IGN) 

     try: 
     # Fork a second child and exit immediately to prevent zombies. This 
     # causes the second child process to be orphaned, making the init 
     # process responsible for its cleanup. And, since the first child is 
     # a session leader without a controlling terminal, it's possible for 
     # it to acquire one by opening a terminal in the future (System V- 
     # based systems). This second fork guarantees that the child is no 
     # longer a session leader, preventing the daemon from ever acquiring 
     # a controlling terminal. 
     pid = os.fork() # Fork a second child. 
     except OSError, e: 
     raise Exception, "%s [%d]" % (e.strerror, e.errno) 

     if (pid == 0): # The second child. 
     # Since the current working directory may be a mounted filesystem, we 
     # avoid the issue of not being able to unmount the filesystem at 
     # shutdown time by changing it to the root directory. 
     os.chdir(WORKDIR) 
     # We probably don't want the file mode creation mask inherited from 
     # the parent, so we give the child complete control over permissions. 
     os.umask(UMASK) 
     else: 
     # exit() or _exit()? See below. 
     os._exit(0) # Exit parent (the first child) of the second child. 
    else: 
     # exit() or _exit()? 
     # _exit is like exit(), but it doesn't call any functions registered 
     # with atexit (and on_exit) or any registered signal handlers. It also 
     # closes any open file descriptors. Using exit() may cause all stdio 
     # streams to be flushed twice and any temporary files may be unexpectedly 
     # removed. It's therefore recommended that child branches of a fork() 
     # and the parent branch(es) of a daemon use _exit(). 
     os._exit(0) # Exit parent of the first child. 
Cuestiones relacionadas