この質問は3年前に行われたもので、回答の基本的な詳細は変更されていませんが、「Windows Pythonデーモン」検索での普及を考えると、将来のGoogleの到着のためにいくつかの議論を追加することが役立つかもしれないと思いました。
質問には実際には2つの部分があります。
- Pythonスクリプトは、無期限に実行される独立したプロセスを生成できますか?
- PythonスクリプトはWindowsシステムでUnixデーモンのように機能できますか?
最初の答えは明白です。すでに指摘したように; キーワードとsubprocess.Popen
一緒に使用するだけで十分です。creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
import subprocess
independent_process = subprocess.Popen(
'python /path/to/file.py',
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)
少なくとも私の経験でCREATE_NEW_CONSOLE
は、ここでは必要ないことに注意してください。
そうは言っても、この戦略の動作は、Unixデーモンに期待するものとはまったく同じではありません。正常に動作するUnixデーモンを構成するものについては、他の場所で詳しく説明していますが、要約すると次のようになります。
- 開いているファイル記述子を閉じます(通常はすべてですが、一部のアプリケーションでは一部の記述子を閉じないように保護する必要があります)
- 「DirectoryBusy」エラーを防ぐために、プロセスの作業ディレクトリを適切な場所に変更します
- ファイルアクセス作成マスクを変更する(
os.umask
Pythonの世界で)
- アプリケーションをバックグラウンドに移動し、開始プロセスからアプリケーションを切り離します
STDIN
、、STDOUT
をSTDERR
別のストリーム(多くの場合)にリダイレクトすることを含め、端末から完全に離婚しDEVNULL
、制御端末の再取得を防ぎます
- 特に信号を処理します
SIGTERM
。
状況の現実は、オペレーティングシステムとしてのWindowsがデーモンの概念を実際にサポートしていないということです。ターミナルから(またはエクスプローラーからの起動など、他のインタラクティブなコンテキストで)起動するアプリケーションは引き続き実行されます。制御アプリケーション(この例ではPython)にウィンドウのないGUIが含まれていない限り、ウィンドウが表示されます。さらに、Windowsのシグナル処理はひどく不十分であり、独立したPythonプロセスにシグナルを送信しようとすると(ターミナルの閉鎖に耐えられないサブプロセスとは対照的に)、ほとんどの場合、クリーンアップなしでそのPythonプロセスがすぐに終了します(finally:
、いいえatexit
、いいえ__del__
など)。
アプリケーションをWindowsサービスにロールインすることも、多くの場合実行可能な代替手段ですが、完全には適合しません。同じことが使用にも当てはまりますpythonw.exe
(最近のすべてのWindows Pythonバイナリに同梱されているウィンドウレスバージョンのPython )。特に、信号処理の状況を改善することができず、端末からアプリケーションを簡単に起動して起動時に対話することはできません(たとえば、動的な起動引数をスクリプトに配信するために、たとえばパスワード、ファイルなど)パスなど)、前「デーモン化」。さらに、Windowsサービスにはインストールが必要です。これは、実行時に「デーモン」を最初に呼び出したときにすばやく実行できますが、ユーザーのシステム(レジストリなど)を変更します。 Unixの世界。
pythonw.exe
それを踏まえると、を使用してサブプロセスを起動することsubprocess.CREATE_NEW_PROCESS_GROUP
は、従来のUnixデーモンをエミュレートするPythonプロセスに相当するWindowsにおそらく最も近いものであると私は主張します。ただし、それでも信号処理とスタートアップ通信の追加の課題が残ります(コードをプラットフォームに依存させることは言うまでもなく、これは常に苛立たしいことです)。
とはいえ、将来この問題が発生する人のために、適切なUnixデーモン化と上記の戦略の両方をラップするdaemonikerというライブラリを作成しました。また、(UnixシステムとWindowsシステムの両方で)信号処理を実装し、pickleを使用してオブジェクトを「デーモン」プロセスに渡すことができます。何よりも、クロスプラットフォームのAPIがあります。
from daemoniker import Daemonizer
with Daemonizer() as (is_setup, daemonizer):
if is_setup:
# This code is run before daemonization.
do_things_here()
# We need to explicitly pass resources to the daemon; other variables
# may not be correct
is_parent, my_arg1, my_arg2 = daemonizer(
path_to_pid_file,
my_arg1,
my_arg2
)
if is_parent:
# Run code in the parent after daemonization
parent_only_code()
# We are now daemonized, and the parent just exited.
code_continues_here()