2014-10-19 1 views
3

Я думал, что процессы Python называют их функции atexit, когда они завершаются. Обратите внимание, что я использую Python 2.7. Вот простой пример:Процесс Python, который соединен, не будет вызывать atexit

from __future__ import print_function 
import atexit 
from multiprocessing import Process 


def test(): 
    atexit.register(lambda: print("atexit function ran")) 

process = Process(target=test) 
process.start() 
process.join() 

Я ожидаю, что это напечатает функцию atexit ran, но это не так.

Обратите внимание, что этот вопрос: Python process won't call atexit похож, но включает в себя процессы, которые завершаются с сигналом, и ответ предполагает перехват этого сигнала. Процессы в этом вопросе выходят изящно, поэтому (насколько я могу судить, так или иначе), что вопрос & ответ не применяется (если только эти Процессы не выходят из-за сигнала каким-то образом?).

+0

@MichaelBrennan этот вопрос включает в себя процессы, которые заканчиваются сигналом. Мои процессы просто изящно выходят из строя, так что это не дубликат (исправление, размещенное там, не применимо здесь, насколько я могу судить, если только мои тоже не будут убиты сигналом) – nonagon

+0

Вы правы, так или иначе Я делаю вывод, что сигнал используется даже без 'terminate()'. Я удалил комментарий дублирования. Возможно, вы можете настроить обработчик сигналов и попытаться выяснить, есть ли какие-либо сигналы? –

+0

Код выхода (то есть process.exitcode, оцененный после выполнения соединения) равен нулю, насколько я могу судить. Если я завершаю процесс, я получаю отрицательный код выхода, как ожидалось из документов. Так что я довольно смущен! Я не могу представить, что это фундаментальное явление нарушено, но я не могу найти доказательств в любом месте, что это не должно работать, как я ожидаю. – nonagon

ответ

3

Я провел некоторое исследование, посмотрев, как это реализовано в CPython. Предполагается, что вы работаете в Unix. Если вы работаете в Windows, это может быть недействительным, так как отличается реализация процессов в multiprocessing.

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

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


Вот отрывок из Popen класса для CPython 2.7, используемый для порождения процессов. Обратите внимание, что последний оператор разветвленного процесса - это вызов os._exit().

# Lib/multiprocessing/forking.py 

class Popen(object): 

    def __init__(self, process_obj): 
     sys.stdout.flush() 
     sys.stderr.flush() 
     self.returncode = None 

     self.pid = os.fork() 
     if self.pid == 0: 
      if 'random' in sys.modules: 
       import random 
       random.seed() 
      code = process_obj._bootstrap() 
      sys.stdout.flush() 
      sys.stderr.flush() 
      os._exit(code) 

В Python 3.4, то os._exit() все еще там, если вы начинаете процесс порождения, который является по умолчанию. Но, похоже, вы можете изменить его, см. Contexts and start methods для получения дополнительной информации. Я не пробовал, но, возможно, используя метод start spawn будет работать? Недоступно для Python 2.7.

+0

Это здорово, спасибо за то, что вы поняли это! Похоже, что многопроцессорная обработка. В документах Process необходимо явно указать это ограничение. Во всяком случае, я придумаю другой механизм для решения этого в моем случае. – nonagon

Смежные вопросы