процесс порождения из питона - PullRequest
11 голосов
/ 10 июня 2009

Я порождаю скрипт, который долго запускается из веб-приложения, например:

os.spawnle(os.P_NOWAIT, "../bin/producenotify.py", "producenotify.py", "xx",os.environ)

скрипт успешно создается и работает, но пока он не закончится, я не могу освободить порт, используемый веб-приложением, или, другими словами, я не могу перезапустить веб-приложение. как создать процесс и сделать его полностью независимым от веб-приложения?

это на ОС Linux.

Ответы [ 2 ]

26 голосов
/ 10 июня 2009

Как пояснил @mark, это система Linux, скрипт может легко стать полностью независимым, то есть демон , следуя этому рецепту . (Вы также можете сделать это в родительском элементе после os.fork и только затем os.exec... дочернего процесса).

Редактировать: чтобы уточнить некоторые детали, см. Комментарий wrt @ mark к моему ответу: привилегии суперпользователя не нужны, чтобы «демонизировать» процесс согласно рецептам поваренной книги, и нет необходимости изменять текущий рабочий каталог (хотя код в рецепте делает это и более того, это не самая важная часть - скорее это правильная логическая последовательность вызовов fork, _exit и setsid). Различные os.exec... варианты, которые не оканчиваются на e, используют среду родительского процесса, поэтому эта часть также проста - см. Онлайн-документы Python .

Чтобы ответить на предложения, высказанные в комментариях и ответах других: я считаю, что subprocess и multiprocessing сами по себе не демонизируют дочерний процесс, что, по-видимому, и нужно @mark; скрипт может сделать это для себя, но так как некоторый код должен выполнять fork s и setsid, мне кажется, лучше держать все нерест на этой плоскости низкого уровня, а не В процессе работы смешайте несколько высокоуровневого и низкоуровневого кода.

Вот значительно сокращенная и упрощенная версия рецепта по указанному выше URL, специально предназначенная для вызова в родительском элементе для порождения дочернего элемента демона - таким образом, код также может быть использован для выполнения не-Python исполняемых файлов. Как указано, код должен соответствовать описанным потребностям @mark, конечно, он может быть адаптирован разными способами - я настоятельно рекомендую ознакомиться с оригинальным рецептом и его комментариями и обсуждениями, а также с книгами, которые он рекомендует, для получения дополнительной информации.

import os
import sys

def spawnDaemon(path_to_executable, *args)
    """Spawn a completely detached subprocess (i.e., a daemon).

    E.g. for mark:
    spawnDaemon("../bin/producenotify.py", "producenotify.py", "xx")
    """
    # fork the first time (to make a non-session-leader child process)
    try:
        pid = os.fork()
    except OSError, e:
        raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
    if pid != 0:
        # parent (calling) process is all done
        return

    # detach from controlling terminal (to make child a session-leader)
    os.setsid()
    try:
        pid = os.fork()
    except OSError, e:
        raise RuntimeError("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
        raise Exception, "%s [%d]" % (e.strerror, e.errno)
    if pid != 0:
        # child process is all done
        os._exit(0)

    # grandchild process now non-session-leader, detached from parent
    # grandchild process must now close all open files
    try:
        maxfd = os.sysconf("SC_OPEN_MAX")
    except (AttributeError, ValueError):
        maxfd = 1024

    for fd in range(maxfd):
        try:
           os.close(fd)
        except OSError: # ERROR, fd wasn't open to begin with (ignored)
           pass

    # redirect stdin, stdout and stderr to /dev/null
    os.open(os.devnull, os.O_RDWR)  # standard input (0)
    os.dup2(0, 1)
    os.dup2(0, 2)

    # and finally let's execute the executable for the daemon!
    try:
      os.execv(path_to_executable, args)
    except Exception, e:
      # oops, we're cut off from the world, let's just give up
      os._exit(255)
12 голосов
/ 10 июня 2009

Вы можете использовать многопроцессорную библиотеку для порождения процессов. Базовый пример показан здесь:

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
...