Python标准库无daemonize函数,因其依赖Unix系统调用(如fork/setsid)且Windows不支持;手动实现易出错,推荐用python-daemon库或systemd服务替代。

为什么 daemonize 不是标准库函数
Python 标准库没有提供开箱即用的 daemonize 函数,因为守护进程行为高度依赖操作系统(尤其是 Unix-like 系统的 fork / setsid / umask / stdin/stdout/stderr 重定向等),而 Windows 完全不支持传统 Unix 守护模式。试图用纯 Python 模拟会导致不可靠或平台断裂。
常见错误是直接用 os.fork() + os.setsid() 手动实现,但漏掉关键步骤(比如关闭继承的文件描述符、重设 umask、chdir 到根目录),结果进程仍卡在终端、日志写入失败、或被 systemd 拒绝管理。
- 必须调用
os.chdir("/"),否则工作目录可能被挂载点锁定 - 必须关闭所有已打开的文件描述符(
sys.stdin/sys.stdout/sys.stderr之外),否则子进程可能意外持有设备句柄 -
os.setsid()前必须先os.fork()并让父进程退出,否则会报Process group leader cannot call setsid
用 python-daemon 库最稳妥
第三方库 python-daemon 封装了全部 POSIX 守护规范细节,且兼容 Python 3.7+ 和主流 Linux 发行版。它不是简单包装 fork,而是严格遵循《UNIX Network Programming》中定义的 daemonization 流程。
安装后,核心用法是继承 daemon.DaemonContext 并重写 run() 方法:
立即学习“Python免费学习笔记(深入)”;
from daemon import DaemonContext from daemon.pidfile import PIDLockFilewith DaemonContext( pidfile=PIDLockFile('/var/run/myapp.pid'), working_directory='/opt/myapp', umask=0o022, signal_map={ 'SIGTERM': lambda signum, frame: cleanup_and_exit(), } ): main_loop() # 这里放你的实际业务逻辑
注意:DaemonContext 默认会重定向 stdin/stdout/stderr 到 /dev/null;若需日志,应显式配置 logging 模块并指向文件路径,不能依赖 print。
systemd 服务替代传统守护进程
现代 Linux(如 Ubuntu 16.04+、CentOS 7+)默认使用 systemd,它原生管理进程生命周期,不再需要程序自己 fork 成守护进程。此时更推荐写一个 .service 文件,让 systemd 负责后台化、重启、日志采集等。
例如 /etc/systemd/system/myapp.service:
[Unit] Description=My Python App After=network.target[Service] Type=simple User=myuser WorkingDirectory=/opt/myapp ExecStart=/usr/bin/python3 /opt/myapp/app.py Restart=always RestartSec=10 StandardOutput=journal StandardError=journal
[Install] WantedBy=multi-user.target
这样启动:sudo systemctl daemon-reload && sudo systemctl enable myapp && sudo systemctl start myapp。好处是无需修改 Python 代码,日志自动进 journalctl -u myapp,且能响应 SIGTERM 正常退出。
容易忽略的是:Type=simple 表示主进程就是服务主体,不要在 app.py 里再调用 daemonize —— 否则 systemd 会认为进程异常退出。
Windows 下怎么处理
Windows 没有 fork 或 setsid,也没有传统守护概念。如果必须长期运行,正确做法是注册为 Windows Service,用 pywin32 提供的 win32serviceutil 模块。
关键点:
- 必须以管理员权限安装服务:
python myservice.py install - 服务类需继承
win32serviceutil.ServiceFramework,并在SvcDoRun中写主循环 - 不能使用
input()、print()或任何阻塞控制台的操作,否则服务启动失败 - 日志建议写入 Windows 事件日志(
win32evtlog)或自定义文件,避免 stdout/stderr
跨平台项目若强行统一用 python-daemon,在 Windows 上会直接抛 NotImplementedError,这点必须提前检查运行环境。










