守护进程一直是程序开发中不可或缺的一部分,它能够在后台持续运行,不会占用用户终端,脱离终端的控制。在日常编程中,我们经常会用类似
php think...
、
php artisan...
、
php yii...
等命令启动需要长期执行的任务,并通过
nohup
将其挂载到后台保持长期运行。类似地,在Workerman中,我们也会使用
php index.php start
的命令来启动进程,但不同的是,它不需要利用
nohup
便可以挂载到后台运行。那么,究竟是如何实现的呢?为了解决这个疑问,本文将重点深入分析Workerman守护进程的实现原理。
首先,我们先了解一些进程相关的知识:
以上概念有时候比较难理解,但我们可以通过一个例子来理解。执行命令
php index.php
会产生进程
61052
,其父进程为Bash进程
8243
,接着通过Fork创建了子进程
61053
,其父进程为
61052
,这两个进程共享相同的进程组
61052
和会话
8243
。调用posix_setsid函数会为子进程
61053
开启新的进程组
61053
和新的会话
61053
,最后子进程
61053
通过Fork创建了子进程
61054
,使进程
61053
升级成了父进程,形成了守护进程。
为了更清楚地理解这些过程,我们可以执行下面的代码进行分析:
0 ) {
echoMsg("parent1", "退出了该进程");
exit;
}
echoMsg("child1");
if (-1 === \posix_setsid()) {
throw new Exception("Setsid fail");
}
echoMsg("child1");
$pid = pcntl_fork();
if ( $pid < 0 ){
exit('fork error');
} elseif( $pid > 0 ) {
echoMsg("parent2", "退出了该进程");
exit;
}
echoMsg("child2", "保留了该进程");
sleep(100);
上面的代码所产生的进程信息即为所述,如果有兴趣,建议自行执行代码并进行分析,可能会有新的收获。接下来,我们看一下Workerman的Worker.php文件中554行的runAll方法中的static::daemonize()函数。其实现流程和上述例子几乎一样。此外,这里还使用了umask函数,其主要作用是为该进程所创建的文件或目录赋予相应的权限,以保证可以对文件或目录进行操作。
守护进程在Workerman中是非常重要的一部分,它确保了Workerman进程的稳定性。相比我们通过使用
nohup
命令启动的程序,在后台运行时会有时无声无息地挂掉的情况,或许读者中有这种经历。当然,市面上也有一些开源的守护进程管理软件,比如supervisor等。除此之外,还有人会利用会话终端screen、tmux等工具来实现。实际上,守护进程的实现方式多种多样,本文仅旨在分析Workerman中守护进程的实现原理,同时提出了在PHP中实现守护进程模式的例子,希望对读者有所帮助。
感谢阅读,个人观点仅供参考,欢迎在评论区发表不同观点。
欢迎关注、分享、点赞、收藏、在看,我是微信公众号「码农先森」作者。