Процесс Python не будет вызывать atexit - PullRequest
20 голосов
/ 30 марта 2010

Я пытаюсь использовать atexit в Process, но, к сожалению, это не похоже на работу. Вот пример кода:

import time
import atexit
import logging
import multiprocessing

logging.basicConfig(level=logging.DEBUG)

class W(multiprocessing.Process):
    def run(self):
        logging.debug("%s Started" % self.name)

        @atexit.register
        def log_terminate():
             # ever called?
             logging.debug("%s Terminated!" % self.name)

        while True:
            time.sleep(10)

@atexit.register
def log_exit():
    logging.debug("Main process terminated")

logging.debug("Main process started")

a = W()
b = W()
a.start()
b.start()
time.sleep(1)
a.terminate()
b.terminate()

Вывод этого кода:

DEBUG:root:Main process started
DEBUG:root:W-1 Started
DEBUG:root:W-2 Started
DEBUG:root:Main process terminated

Я ожидал бы, что W.run.log_terminate() будет вызываться при вызове a.terminate() и b.terminate(), а вывод будет чем-то подобным (выделение добавлено)!:

DEBUG:root:Main process started
DEBUG:root:W-1 Started
DEBUG:root:W-2 Started
<b>DEBUG:root:W-1 Terminated!
DEBUG:root:W-2 Terminated!</b>
DEBUG:root:Main process terminated

Почему это не работает, и есть ли лучший способ записать сообщение (из контекста Process), когда Process завершен?

Спасибо за ваш вклад - это очень ценится.

Решение

РЕДАКТИРОВАТЬ: На основе решения, предложенного Алексом Мартелли, следующие работы, как ожидалось:

import sys
import time
import atexit
import signal
import logging
import multiprocessing

logging.basicConfig(level=logging.DEBUG)

class W(multiprocessing.Process):
    def run(self):
        logging.debug("%s Started" % self.name)

        def log_terminate(num, frame):
             logging.debug("%s Terminated" % self.name)
             sys.exit()
        signal.signal(signal.SIGTERM, log_terminate)
        while True:
            time.sleep(10)

@atexit.register
def log_exit():
    logging.debug("Main process terminated")

logging.debug("Main process started")
a = W()
b = W()
a.start()
b.start()
time.sleep(1)
a.terminate()
b.terminate()

Стоит отметить следующий комментарий в документации <a href="http://docs.python.org/library/atexit.html" rel="noreferrer">atexit</a>:

Примечание: функции, зарегистрированные через этот модуль, не вызываются, когда программа прерывается сигналом, когда обнаруживается фатальная внутренняя ошибка Python или когда вызывается os._exit ().

1 Ответ

18 голосов
/ 30 марта 2010

Как документы говорят,

В Unix это делается с помощью SIGTERM сигнал; в Windows TerminateProcess () используется. Обратите внимание, что обработчики выхода и наконец-то пунктов и т. д. не будет казнены.

Если вы работаете в Unix, вы должны иметь возможность перехватывать SIGTERM с сигналом и выполнять любые «действия по завершению», которые вам нужны; однако я не знаю кроссплатформенного решения.

...