web-dev-qa-db-ja.com

効率的なPythonデーモン

バックグラウンドでpythonスクリプトを実行し、60秒ごとにタスクを繰り返すことができる方法に興味がありました。

ループを実行し、60秒間待機させてから再度ロードすることを考えていましたが、それについて何か気分が悪くなりました。

30
Kyle Hotchkiss

あなたのアイデアは、まさにあなたが望むものだと思います。例えば:

_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秒間スリープ状態になります。その時間が経過すると、OSはプログラムを起動し、do_something()関数を実行してから、スリープ状態に戻します。プログラムがスリープしている間は、非常に効率的に何もしていません。これは、バックグラウンドサービスを記述するための一般的なパターンです。

これをコマンドラインから実際に実行するには、&を使用できます。

_$ python background_test.py &
_

これを行うと、スクリプトからの出力は、開始元と同じ端末に送られます。これを避けるために出力をリダイレクトできます:

_$ python background_test.py >stdout.txt 2>stderr.txt &
_
9
Greg Hewgill

独自のデーモンを記述するのではなく、代わりに python-daemon を使用してください! python-daemon は、 PEP 314 、 "標準デーモンプロセスライブラリ"の適切に動作するデーモン仕様を実装します。

この質問に対する受け入れられた答えに基づいてサンプルコードを含めました。コードはほとんど同じに見えますが、重要な根本的な違いがあります。 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 answer では、 python-daemon を使用することの多くの利点について詳しく説明しています。

96
aculich

Gregが説明したように、シェルで&を使用するのはおそらく最も簡単な方法です。

本当に強力なデーモンを作成したい場合は、os.fork()コマンドを調べる必要があります。

Wikipedia の例:

_#!/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()ブロック内に配置できます。

&を使用してこれを起動する必要はなく、実行をもう少しカスタマイズすることができます。

6
Kevin Dolan