Как оповестить демона о пиде - PullRequest
0 голосов
/ 16 января 2019

Итак, я промочил ноги на python, пытаясь создать систему напоминаний, которая связана с пользовательским интерфейсом уведомлений gnome. Основная идея заключается в том, что вы вводите команду в вашу оболочку, например remind me to check on dinner in 20 min, а затем через 20 минут вы получаете уведомление на рабочем столе с надписью «проверка на ужин». Я делаю это с помощью сценария, который анализирует сообщение и записывает время отправки уведомления и сообщение, которое следует отправить в файл журнала.

Уведомления запускаются демоном Python. Я использую этот дизайн демона, который нашел онлайн . Проблема, которую я вижу, состоит в том, что когда этот демон работает, он забирает 100% моего процессора! Я сократил весь код, который делал демон, и у меня все еще есть эта проблема, когда все, что делает демон, это

while True:
 last_modified = os.path.getmtime(self.logfile)

Я предполагаю, что это плохой подход, и вместо этого я должен уведомлять демона, когда появляется новое напоминание, а затем большую часть времени демон сна должен напоминать. Сейчас это всего лишь идея, но мне трудно найти ресурсы о том, «как уведомить процесс», когда все, что я знаю, это pid демонов. Поэтому, если я приостановлю работу демона с помощью чего-то вроде time.sleep(time_to_next_notification), будет ли для меня способ отправить сигнал демону, сообщив ему, что появилось новое напоминание?

1 Ответ

0 голосов
/ 16 января 2019

Хотя я считаю, что вам лучше использовать решение типа сервер-клиент, который прослушивает порт, то, что вы запрашиваете, возможно на 100% с использованием signal и os библиотек. Этот подход не будет хорошо работать с многопоточными программами, так как сигналы обрабатываются только родительским потоком в python. Кроме того, окна не реализуют сигналы таким же образом, поэтому параметры более ограничены.

Сигналы

Процесс "клиент" может отправлять произвольные сигналы, используя os.kill(pid, signal). Вам нужно будет просмотреть доступные сигналы и определить, какой из них вы хотите использовать (signal.NSIG может быть хорошим вариантом, поскольку он не должен давить на любое другое поведение по умолчанию).

Процесс "демон" при запуске должен зарегистрировать обработчик для того, что делать, когда он получает выбранный вами сигнал. Обработчик - это функция, которую вы должны определить, которая получает сам полученный сигнал, а также текущий выполняемый кадр стека (def handler(signum, frame):). Если вы делаете только одну вещь с этим обработчиком, и ему не нужно знать, что происходило, когда он вызывался, вы, вероятно, можете игнорировать оба эти параметра. Затем вы должны зарегистрировать обработчик с помощью signal.signal ex: signal.signal(signal.NSIG, handler).

Оттуда вы захотите найти подходящий способ ожидания следующего сигнала, не затрачивая слишком много ресурсов. Это может быть так же просто, как зацикливание на os.sleep команда, или вы могли бы попытаться получить фантазию. Я не уверен на 100%, как возобновится выполнение при возврате из обработчика сигнала, поэтому вам, возможно, придется позаботиться о глубине рекурсии (т.е. убедитесь, что вы не повторяете каждый раз, когда обрабатывается сигнал, или вы только когда-либо будете возможность обрабатывать ограниченное количество сигналов перед повторным запуском).

Сервер

Наличие процесса прослушивания порта (обычно называемого сервером, но функционально аналогичного описанию вашего «демона») вместо прослушивания сигналов операционной системы имеет несколько основных преимуществ.

  • Порты могут отправлять данные, когда сигналы могут вызывать только события
  • Порты больше похожи на кроссплатформенные
  • Порты играют хорошо [r] с многопоточностью
  • Порты позволяют легко отправлять сообщения по сети (например, создавать напоминания с телефона и выполнять на ПК)

Ожидание нескольких вещей одновременно

Чтобы решить необходимость ожидания нескольких процессов одновременно (прослушивание ввода, а также ожидание доставки следующего уведомления), у вас есть довольно много вариантов:

  • Сигналы на самом деле могут быть хорошим вариантом использования, поскольку signal.SIGALRM можно использовать как удобно переустанавливаемый будильник (если вы используете UNIX). Вы должны настроить обработчик так же, как и раньше, и просто установить будильник для следующего уведомления. После установки будильника вы можете просто возобновить прослушивание порта для новых задач. Если приходит новое задание, повторная установка будильника переопределит существующее, поэтому обработчику потребуется извлечь следующее уведомление в очереди и заново установить будильник, как только будет выполнено первое задание.

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

  • Наиболее элегантное решение, вероятно, заключалось бы в использовании asyncio сопрограмм, однако я не так хорошо разбираюсь в asyncio и признаю, что они немного более запутанны, чем потоки.

...