Python のデーモンプロセスとは
Python のデーモンプロセスは、メインプロセスが終了すると自動的に終了するバックグラウンドプロセスです。Process の daemon 属性を True に設定することで作成できます。
デーモンプロセスの基本
デーモンプロセスは、メインプロセスの終了時に自動的に終了します。
from multiprocessing import Process
import time
def background_task():
while True:
print("Background running...")
time.sleep(1)
if __name__ == "__main__":
p = Process(target=background_task)
p.daemon = True # デーモンプロセスに設定
p.start()
time.sleep(3)
print("Main process finished")
# メインプロセスが終了すると、デーモンプロセスも終了
メインプロセスが終了すると、明示的に join() を呼ばなくてもデーモンプロセスは終了します。
daemon 属性の設定タイミング
daemon 属性は start() を呼ぶ前に設定する必要があります。
from multiprocessing import Process
def task():
pass
p = Process(target=task)
p.daemon = True # start() の前に設定
p.start()
# p.daemon = True # start() の後に設定するとエラー
start() 後に変更しようとすると、RuntimeError が発生します。
コンストラクタで指定する
Process のコンストラクタで直接 daemon を指定することもできます。
from multiprocessing import Process
def task():
print("Task running")
if __name__ == "__main__":
p = Process(target=task, daemon=True)
p.start()
p.join()
コンストラクタで指定するほうがコードがすっきりします。
デーモンプロセスの特徴
自動終了
メインプロセスが終了すると、デーモンプロセスも強制終了される。クリーンアップ処理は実行されない。
子プロセスの作成不可
デーモンプロセスは新しい子プロセスを作成できない。作成しようとするとエラーになる。
デーモンと非デーモンの違い
非デーモンプロセス
メインプロセスは子プロセスの終了を待つ。join() を呼ばないと、ゾンビプロセスが残る可能性がある。
デーモンプロセス
メインプロセスの終了時に自動的に終了する。バックグラウンドタスクに適している。
使い分けの例
非デーモンプロセスは、結果が必要な処理に使います。
from multiprocessing import Process, Queue
def compute(q):
result = 42 # 何かの計算
q.put(result)
if __name__ == "__main__":
q = Queue()
p = Process(target=compute, args=(q,))
p.start()
p.join()
print(q.get()) # 42
デーモンプロセスは、ログ収集やモニタリングなどのバックグラウンドタスクに使います。
from multiprocessing import Process
import time
def monitor():
while True:
# システムの監視処理
print("Monitoring...")
time.sleep(5)
if __name__ == "__main__":
p = Process(target=monitor, daemon=True)
p.start()
# メインの処理
for i in range(3):
print(f"Main task {i}")
time.sleep(2)
print("Done")
# monitor プロセスは自動的に終了
デーモンプロセスの終了に注意
デーモンプロセスは強制終了されるため、ファイルへの書き込みやリソースの解放が完了しない可能性があります。
from multiprocessing import Process
import time
def write_log():
with open("log.txt", "w") as f:
for i in range(10):
f.write(f"Log {i}\n")
time.sleep(1)
f.flush() # これが実行されない可能性
if __name__ == "__main__":
p = Process(target=write_log, daemon=True)
p.start()
time.sleep(3)
# メインプロセスが終了し、write_log は途中で終了
重要なデータを扱う処理にはデーモンプロセスを使わないか、適切な同期メカニズムを導入してください。