Python でデーモンを作成することについては、こののような質問がすでにいくつかあり、その部分にうまく答えています。
では、デーモンにバックグラウンドでの作業をさせるにはどうすればよいでしょうか?
ご想像のとおり、スレッドは明らかな答えです。しかし、考えられる複雑性が 3 つあります。
まず、シャットダウンがあります。運が良ければ、crunchData
データの破損や (重大な) 作業の損失なしに、関数をいつでもすぐに強制終了できます。その場合:
def worker():
while True:
crunchData()
# ... somewhere in the daemon startup code ...
t = threading.Thread(target=worker)
t.daemon = True
t.start()
注意してt.daemon
ください。「デーモンスレッド」は、プログラムがデーモンであることとは何の関係もありません。これは、メイン プロセスを終了するだけですぐに強制終了されることを意味します。
しかし、crunchData
殺せない場合はどうなりますか?次に、次のようなことをする必要があります。
quitflag = False
quitlock = threading.Lock()
def worker():
while True:
with quitlock:
if quitflag:
return
crunchData()
# ... somewhere in the daemon startup code ...
t = threading.Thread(target=worker)
t.start()
# ... somewhere in the daemon shutdown code ...
with quitlock:
quitflag = True
t.join()
の各反復にはそれほど時間がかからないと想定してcrunchData
います。その場合はquitFlag
、関数自体で定期的に確認する必要があります。
その間、バックグラウンド スレッドが生成しているデータにリクエスト ハンドラがアクセスする必要があります。そこでも何らかの同期が必要になります。
明らかなことは、別のを使用することですLock
。crunchData
しかし、そのデータに頻繁に書き込んでいる可能性は十分にあります。一度に 10 秒間ロックを保持すると、リクエスト ハンドラは 10 秒間ブロックする可能性があります。しかし、ロックの取得と解放を 100 万回繰り返すと、実際の作業よりも時間がかかる可能性があります。
代替手段の 1 つは、データをダブル バッファリングすることです。crunchData
新しいコピーに書き込みを行い、それが完了したら、簡単にロックを取得して を設定しcurrentData = newData
ます。
ユースケースによってはQueue
、 、ファイル、またはその他のものがさらに単純になる場合があります。
最後に、crunchData
おそらく多くの CPU 作業を行っています。リクエスト ハンドラーが CPU の作業をほとんど行わないようにする必要があります。そうしないと、2 つのスレッドが GIL をめぐって競合するため、各リクエストがかなり遅くなります。通常、これは問題ありません。そうである場合は、 a のmultiprocessing.Process
代わりに a を使用しますThread
(これにより、2 つのプロセス間でのデータの共有または受け渡しが少し複雑になりますが、それでもそれほど悪くはありません)。