python-daemon通过独立函数调用无法正常工作的问题求助
解决Python-daemon独立函数创建守护进程无法写入文件的问题
我来帮你理清这个问题的根源~当你把守护进程的创建逻辑抽到独立函数里时,核心问题出在文件对象的生命周期和进程fork后的资源继承规则上,咱们一步步拆解:
问题根源分析
你原来在if __name__ == '__main__'里能成功运行,是因为:
- 在父进程里打开了文件,拿到了内核级的文件描述符
- 用
files_preserve把这个描述符保留下来,让子进程(守护进程)能继承 - 父进程的文件对象在进入守护上下文后还没被销毁,刚好能被子进程复用(这其实是个巧合,严格来说fork后父进程的Python对象并不会被子进程完全继承)
但放到独立函数里时,大概率你的代码是类似这样的:
from daemon import DaemonContext def start_daemon(): my_file = open("my_file", "w+") with DaemonContext(files_preserve=[my_file.fileno()]): main() def main(): my_file.write("Daemon creation was successful") my_file.close() if __name__ == "__main__": start_daemon()
这里的my_file是start_daemon的局部变量,当守护进程fork完成后,父进程会退出,start_daemon的函数栈被销毁,my_file对象也被回收——子进程虽然继承了文件描述符,但原来的Python文件对象已经不存在了,自然没法写文件。
两种解决方案
方案1:在守护进程内部打开文件(推荐)
这是最稳妥的方式,直接在守护进程启动后的上下文里处理文件IO,完全避免跨进程的对象问题:
from daemon import DaemonContext def main(): # 守护进程启动后,在子进程内部打开文件 with open("my_file", "w+") as my_file: my_file.write("Daemon creation was successful") def start_daemon(): # 不需要files_preserve,因为文件是子进程自己打开的 with DaemonContext(): main() if __name__ == "__main__": start_daemon()
方案2:保留文件描述符,子进程重新构建文件对象
如果必须在父进程里提前打开文件(比如要做预写入操作),可以保留文件描述符,在子进程里重新创建文件对象:
from daemon import DaemonContext import os def main(file_fd): # 从继承的文件描述符重新构建文件对象 with os.fdopen(file_fd, "w+") as my_file: my_file.write("Daemon creation was successful") def start_daemon(): my_file = open("my_file", "w+") file_fd = my_file.fileno() # 父进程先关闭文件对象,但保留内核级的文件描述符 my_file.close() with DaemonContext(files_preserve=[file_fd]): main(file_fd) if __name__ == "__main__": start_daemon()
关键知识点
- 守护进程本质是通过
fork创建的子进程,父进程的Python对象(比如my_file)不会被子进程继承,只有内核级的资源(比如文件描述符)会被传递。 files_preserve的作用是告诉守护进程不要关闭指定的文件描述符,否则默认会关闭所有非标准输入输出的文件描述符。
内容的提问来源于stack exchange,提问作者Cat
相关产品推荐
相关产品推荐

