高效的Python守护进程

36

我很好奇如何在后台运行一个Python脚本,每60秒重复一次任务。我知道可以使用&将某些东西放到后台,对于这种情况是否有效?

我考虑使用循环,让它等待60秒并重新加载,但是感觉不太对劲。


2
这取决于你想要什么。如果你想要安排一个任务定期重复执行,可以看看cron。 - Falmarri
3个回答

110
不要自己编写守护进程,而是使用python-daemonpython-daemon实现了PEP 3143,“标准守护进程库”的规范。
我已经根据这个问题的被接受的答案提供了示例代码,即使代码看起来几乎相同,但有一个重要的基本差异。没有python-daemon你必须使用&将进程放在后台,并且使用nohup使进程在退出终端时不被杀死。相反,这将在运行程序时自动分离终端。
例如:
import daemon
import time

def do_something():
    while True:
        with open("/tmp/current_time.txt", "w") as f:
            f.write("The time is now " + time.ctime())
        time.sleep(5)

def run():
    with daemon.DaemonContext():
        do_something()

if __name__ == "__main__":
    run()

实际运行它的方式是:

python background_test.py

注意这里没有&

此外,另一个stackoverflow答案详细解释了使用python-daemon的许多好处。


1
你可能会感到惊讶,PEP(Python增强建议)的作者和库的作者是同一个人。因此,这个库非常好地实现了该PEP :) - Reishin
1
你说“这个其他的stackoverflow答案”,但是链接到的是一个问题,而不是一个答案。你链接到的问题的被选中的答案(在我发表这个评论时)没有使用python-daemon。也许你想要链接到https://dev59.com/L3RB5IYBdhLWcg3w6LR2#688448? - Bruno Bronosky

16

我认为你的想法几乎完全符合你的要求。例如:

import time

def do_something():
    with open("/tmp/current_time.txt", "w") as f:
        f.write("The time is now " + time.ctime())

def run():
    while True:
        time.sleep(60)
        do_something()

if __name__ == "__main__":
    run()

调用time.sleep(60)将使您的程序休眠60秒。当时间到达时,操作系统将唤醒您的程序并运行do_something()函数,然后将其放回休眠状态。在程序休眠期间,它不能高效地执行任何任务,这是编写后台服务的通用模式。

要从命令行实际运行此程序,可以使用&:

$ python background_test.py &

执行此命令时,脚本的任何输出都将发送到启动该脚本的终端。您可以通过重定向输出来避免这种情况:

$ python background_test.py >stdout.txt 2>stderr.txt &

谢谢,这正是我在寻找的。我所知道的编程零碎知识来自JavaScript,而在那里尝试使用计时器做任何事情都变成了一场噩梦! - Kyle Hotchkiss
1
你可能还想看一下 nohup(例如 nohup python background_test.py),假设你希望守护进程在你退出登录后继续运行。 - Foon
1
有一种更简单的方法可以使用“python-daemon”来完成,这是“标准守护进程库”:https://dev59.com/cm445IYBdhLWcg3w6eXz#8375012 - aculich
1
@user2452250:请查看问题What does if __name__ == "__main__": do? - Greg Hewgill

8

在shell中使用&可能是Greg所描述的最简单的方法。

如果您真的想要创建一个强大的守护进程,您将需要研究os.fork()命令。

来自维基百科的示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, time

def createDaemon():
  """ 
      This function create a service/Daemon that will execute a det. task
  """

  try:
    # Store the Fork PID
    pid = os.fork()

    if pid > 0:
      print 'PID: %d' % pid
      os._exit(0)

  except OSError, error:
    print 'Unable to fork. Error: %d (%s)' % (error.errno, error.strerror)
    os._exit(1)

  doTask()

def doTask():
  """ 
      This function create a task that will be a daemon
  """

  # Open the file in write mode
  file = open('/tmp/tarefa.log', 'w')

  # Start the write
  while True:
    print >> file, time.ctime()
    file.flush()
    time.sleep(2)

  # Close the file
  file.close()

if __name__ == '__main__':

  # Create the Daemon
  createDaemon()

然后你可以在 doTask() 块内放置任何所需的任务。

您无需使用 & 启动此任务,这将允许您进一步自定义执行方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接