如何在给定 pid 的情况下通知守护进程

How to notify a daemon given a pid

所以我一直在尝试 python,试图建立一个与 gnome 通知相关的提醒系统 ui。基本思路是,您在 shell 中键入一个命令,例如 remind me to check on dinner in 20 min,然后在 20 分钟内您会收到一个桌面通知,上面写着 "check on dinner"。我这样做的方法是让脚本解析消息并写入发送通知的时间和应该发送到日志文件的消息。

通知由 python 守护进程触发。我正在使用我发现的这个守护程序设计 online。我看到的问题是当这个守护进程是 运行 时,它占用了我的 cpu 的 100%!我删除了守护进程正在执行的所有代码,当所有守护进程正在执行的是

时,我仍然遇到这个问题
while True:
 last_modified = os.path.getmtime(self.logfile)

我认为这是一个糟糕的方法,我应该改为在有新提醒时通知守护进程,然后提醒守护进程大部分时间应该处于休眠状态。现在这只是一个想法,但当我只知道守护进程 pid 时,我很难在 'how to notify a process' 上找到资源。因此,如果我用 time.sleep(time_to_next_notification) 之类的东西暂停守护进程,我是否可以通过某种方式向守护进程发送信号,让它知道有新的提醒?

虽然我相信您最好使用服务器 - 侦听端口的客户端类型解决方案,但您所要求的是使用 signal and os 库 100% 可能。但是,这种方法不适用于多线程程序,因为信号仅由 python 中的父线程处理。此外,windows 没有以相同的方式实现信号,因此选项更加有限。

信号

"client" 进程可以使用 os.kill(pid, signal) 发送任意信号。您将必须仔细检查可用的信号并确定要使用的信号(signal.NSIG 可能是一个不错的选择,因为它不应影响任何其他默认行为)。

启动时的 "daemon" 进程必须注册一个处理程序,以便在收到您选择的信号时执行操作。处理程序是一个您必须定义的函数,它接收接收到的信号本身以及当前执行的堆栈帧 (def handler(signum, frame):)。如果你只用这个处理程序做一件事,它不需要知道调用它时发生了什么,你可以忽略这两个参数。然后你必须用 signal.signal ex: signal.signal(signal.NSIG, handler).

注册处理程序

从那里你会想找到一些合适的方法来等待下一个信号而不消耗太多资源。这可能就像在 os.sleep 上循环一样简单 命令,或者你可以试着变得花哨。我不确定 100% 如何在从信号处理程序返回时恢复执行,因此您可能需要关注递归深度(即,确保您不会在每次处理信号时都递归,否则您只会能够在需要重新启动之前处理有限数量的信号)。

服务器

让进程监听端口(通常称为服务器,但功能与您的 'daemon' 描述相同)而不是监听操作系统信号有几个主要优点。

  • 端口能够在信号只能触发事件的地方发送数据
  • 端口更相似跨平台
  • Ports 与多线程
  • 配合得很好[r]
  • 端口使通过网络发送消息变得容易(即:从 phone 创建提醒并在 PC 上执行)

一次等待多个东西

为了解决一次等待多个进程的需要(监听输入以及等待传递下一个通知),您有很多选择:

  • 信号实际上可能是一个很好的用例,因为 signal.SIGALRM 可以用作方便的可重新设置的闹钟(如果您使用的是 UNIX)。您可以像以前一样设置处理程序,并为下一个通知设置一个警报。设置警报后,您可以简单地恢复监听端口以获取新任务。如果有新任务进入,再次设置警报将覆盖现有警报,因此处理程序需要检索下一个排队的通知并在完成第一个任务后重新设置警报。

  • 线程可以用于轮询通知任务队列,或者可以创建一个单独的线程来等待每个任务。这不是一个特别优雅的解决方案,但它会有效且易于实施。

  • 最优雅的解决方案可能是使用 asyncio 协同例程,但是我不太精通 asyncio,并且我承认它们比线程更令人困惑.