希望通过django启动一个在后台一直运行的程序. 无论是通过使用多线程(threading),还是多进程(subprocess, multiprocessing, os.fork),页面都会返回内容,但一直处于继续等待的界面.分析原因是在django中启动线程后除非kill掉启动的线程或者线程自己结束,否则django都会认为还有消息要返回.
于是考虑建立一个daemon,在django启动后与其交互.但如此daemon和django要分开启动比较麻烦.决定让daemon在django启动的过程中启动.方法是将建立daemon人过程放在django 的settings.py中.
很意外,django在启动过程中居然加载了5次settings.py文件,我的daemon也启动了5次.而且一开始我的daemon只是简单的通过pipe进行交互:
p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) in, out = p.stdin, p.stdout
之后的控制必须要
from settings import in, out in.writes(cmd + "/n") in.flush()
如上,有三个问题.
1.通过pipe进行命令交互时,若是A启动B,然后A与B进行交互是没问题的,但因为我的程序要封装一层,结果会成为A启动B, B启动C,A与B间通过简单的调用进行交互,B与C间通过PIPE通信,然后A指导B对C发送命令,不知道什么原因,PIPE通信居然不可行了.
2.PIPE通信有个弊端,只能在local端通信,但根据需求之后会有多个服务器的,所以PIPE通信其实不可行.
3.如何防止启动django时启动多个daemon
解决方法:
1.将PIPE通信直接改成socket通信,以后的命令直接通过socket交互,这样以上的问题1与2都解决了
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(("", port)) while True: data, addr = s.recvfrom(1024) if data: print("do something")
2.防止启动多个deamon的方法也很简单,修改上述代码,通过查看端口是否被占用决定是否继续运行.
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: s.bind(("", port)) except: #当端口被使用时直接退出,不再启动 sys.exit(0) while True: data, addr = s.recvfrom(1024) if data: cmd
如果只是简单的新建一个线程daemon或进程daemon,当django退出时,这些伪daemon也会消失.在linux下,想要成为真正的daemon必须如下(参考python cookbook),这样保证django出现意外时客户端依然能保持与守护进程的通信:
try: pid = os.fork() if pid > 0:#退出父进程,进入子进程 sys.exit(0) except: pass #建立session id,脱离当前终端控制 os.chdir('/') os.umask(0) os.setsid() #成为真正的daemon try: pid = os.fork() if pid > 0:#退出父进程,进入子进程,这时真正成为daemon, sys.exit(0) except: pass s = socket.socket(socket.AF_INT, socket.SOCK_DGRAM) try: s.bind(("", port)) except: sys.exit(0) while True: data, addr = s.recvfrom(1024) if data: cmd