Python启动后台进程
所谓后台进程就是脱离当前程序的进程,当前程序退出后,后台进程依然在运行。
在类Unix系统中,简单的方式就是 Double-Fork:https://stackoverflow.com/questions/881388/what-is-the-reason-for-performing-a-double-fork-when-creating-a-daemon
重定向标准输入输出#
在后台进程fork出来后,为不受干扰,需要将标准输入输出重定向,使用下面代码重定向:
read_null = open('/dev/null')
os.dup2(read_null.fileno(), sys.stdin.fileno())
在pytest测试时,pytest为了捕获程序的输入输出,会更改 sys.stdin 到其自己的对象,在获取 fileno 时报异常。解决方法是运行pytest时增加 -s 参数关闭输入输出捕获功能。
也有文章说可以直接设置:
sys.stdin = read_null
目前尚不清楚这两种方式有什么区别。
Windows#
Windows不支持fork,所以无法像Unix类系统一样通过 double-fork 创建后台进程。
Windows下可以通过subprocess库创建进程,指定特别的创建标志后,新进程就会脱离成为独立的进程。https://stackoverflow.com/questions/12843903/how-to-start-daemon-process-from-python-on-windows
subprocess.Popen(executable, creationflags=subprocess.DETACHED_PROCESS, close_fds=True)
这个creationflags的常量中有几个类似的,CREATE_NEW_CONSOLE,CREATE_NEW_PROCESS_GROUP,DETACHED_PROCESS,但这些常量只能在Windows平台下使用,在其它平台下使用时会发现常量定义不存在。https://docs.python.org/3/library/subprocess.html#windows-constants
目前我还没有调研清楚这几个不同的常量有什么区别。
跨平台#
网上有一个跨平台实现后台进程的Python库:https://github.com/Muterra/py_daemoniker
不过其为了实现类似fork的效果,在Windows上会将当前的代码状态写入到文件中,在新进程中执行,尚不清楚这种方式是否会有什么隐患。
另外其代码中写死了通过pythonw.exe运行进程,对于将python打包成一个可执行文件的情况可能不适用。
但其代码还是有一定的参考价值。
Multiprocessing#
Multiprocessing是Python的多进程库,可以用来创建进程,创建进程时像多线程一样指定一个函数作为进程的主函数。
该库支持类Unix操作系统和Windows操作系统,在创建进程时可以指定daemon参数设置进程是Daemon还是Non-Daemon。
不过这里的Daemon并不是我们所说的后台进程,这里的Daemon进程在主进程结束后会立即被结束掉,而Non-Daemon进程在主进程结束时会等待所有Non-Daemon进程结束。
Multiprocessing在开启进程时可以传递一个函数作为进程的主函数,不过这个函数不能是内嵌函数(即定义在其它函数内的函数)。
因为其底层是启动进程后,将函数名称传递过去然后执行,内嵌函数在全局空间中不存在,也就无法找到对应的函数执行。
命名管道#
创建了多个进程后,进程之间的通信就是另外一个问题,我开始想通过命名管道来通信,因为这个是基本上所有操作系统都支持的功能。
不过在跨平台的时候发现又是一个坑,python标准库里面的os.mkfifo()函数只能在Unix类系统下使用!
而且在os.mkfifo()时需要指定一个文件路径,系统会创建出一个文件,而这个文件是不会自动删除的,如果文件已经存在,os.mkfifo()会报错!
这篇文章里面详述了在Windows下如何使用命名管道:https://medium.datadriveninvestor.com/named-pipes-communication-between-python-server-and-python-client-on-window-8cdf64504801
参考资料:#
https://stackoverflow.com/questions/12843903/how-to-start-daemon-process-from-python-on-windows
https://superfastpython.com/daemon-process-in-python/