Nohup и Python -u: он все еще не регистрирует данные в реальном времени

При запуске процесса Python, в фоновом режиме, с

nohup python myscript.py > test.log 2>&1 < /dev/null &

проблема в том, что stdout буферизируется: данные не записываются в реальном времени в test.log, Общее решение этой проблемы - периодически промывать sys.stdout.flush() или даже лучше, как предполагает этот ответ, использовать python -u:

nohup python -u myscript.py > test.log 2>&1 < /dev/null &

Но этого недостаточно. Я заметил, что он работал в течение нескольких часов, а затем перестал работать, то есть через несколько часов test.log больше не пишется в реальном времени, даже если я использовал nohup python -u ...,

1) Это как воспроизвести проблему (у меня стандартный Debian Jessie). Запустите этот файл:

import time
import datetime
while True:
    print datetime.datetime.now()
    time.sleep(60)

с nohup python -u myscript.py > test.log 2>&1 < /dev/null &, Файл журнала будет обновлен в течение нескольких часов, а затем через 3 или 4 часа, больше ничего.

2) Как решить эту проблему, не вставляя stdout.flush() каждые 2 строки в коде (некрасивое решение)?

2 ответа

Если python -u не работает для вас, следующим предложением будет заменить sys.stdout пользовательским классом, который не буферизует вывод.

Магнус Лицка предоставил это решение в списке рассылки

class Unbuffered(object):
    def __init__(self, stream):
        self.stream = stream
    def write(self, data):
        self.stream.write(data)
        self.stream.flush()
    def __getattr__(self, attr):
        return getattr(self.stream, attr)

import sys
sys.stdout = Unbuffered(sys.stdout)
print 'Unbuffered Output'

Я не могу понять, почему Python -u не будет работать на вашем примере, но это должно решить эту проблему для вас.

Есть несколько способов справиться с этим.

  1. Создайте свою собственную небуферизованную функцию вывода и используйте ее вместо print()
импорт системы

журнал регистрации (сообщения):
    sys.stdout.write(MSG)
    sys.stdout.flush()

журнал ("Привет, мир!")
  1. Используйте команду mkfifo, чтобы создать собственное устройство регистрации и записать в него вместо stdout. Используйте отдельную команду для передачи с устройства в файл.

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

Я бы с подозрением относился к nohup. Терминал открывает стандартные потоки ввода / вывода и передает их процессам. Если вы запускаете процесс с nohup, а затем выходите из системы и закрываете терминал, я не уверен, что происходит со стандартными потоками. Возможно, ОС выполняет сборку мусора и закрывает их, оставляя ваш процесс без stdout. Вы действительно должны подумать о написании собственных журналов.

Другие вопросы по тегам