Python のデーモンプロセスとは

Python のデーモンプロセスは、メインプロセスが終了すると自動的に終了するバックグラウンドプロセスです。Processdaemon 属性を 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 は途中で終了

重要なデータを扱う処理にはデーモンプロセスを使わないか、適切な同期メカニズムを導入してください。