深入解析守护进程的实现原理及在PHP中的应用 | 木戈手机站

木戈手机站

当前位置: 首页 » 攻略 » 深入解析守护进程的实现原理及在PHP中的应用

深入解析守护进程的实现原理及在PHP中的应用

守护进程一直是程序开发中不可或缺的一部分,它能够在后台持续运行,不会占用用户终端,脱离终端的控制。在日常编程中,我们经常会用类似

php think...



php artisan...



php yii...

等命令启动需要长期执行的任务,并通过

nohup

将其挂载到后台保持长期运行。类似地,在Workerman中,我们也会使用

php index.php start

的命令来启动进程,但不同的是,它不需要利用

nohup

便可以挂载到后台运行。那么,究竟是如何实现的呢?为了解决这个疑问,本文将重点深入分析Workerman守护进程的实现原理。

首先,我们先了解一些进程相关的知识:

  • 父进程:父进程是生成其他进程的进程。当一个进程创建了另一个进程时,创建者称为父进程,而被创建的进程则称为子进程。父进程可以通过进程标识符(PID)来识别它所创建的子进程。
  • 子进程:子进程是由父进程创建的新进程。子进程继承了父进程的一些属性,例如环境变量、文件描述符等。子进程独立于父进程运行,它可以执行自己的代码,并且具有自己的资源和内存空间。
  • 进程组:进程组是一组相关联的进程的集合。每个进程组都有一个唯一的进程组ID(PGID),用于标识该进程组。进程组通常由一个父进程创建,并且包含了与父进程具有相同会话ID(SID)的所有子进程。
  • 会话:会话是一组关联进程的集合,通常由用户登录到系统开始,直至用户注销或关闭终端会话结束,一个会话中的进程共享相同的控制终端。每个会话都有一个唯一的会话ID(SID),用于标识该会话。会话通常包含一个或多个进程组,其中第一个进程组成为会话的主进程组。

以上概念有时候比较难理解,但我们可以通过一个例子来理解。执行命令

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中实现守护进程模式的例子,希望对读者有所帮助。

感谢阅读,个人观点仅供参考,欢迎在评论区发表不同观点。


欢迎关注、分享、点赞、收藏、在看,我是微信公众号「码农先森」作者。

猜你喜欢
本类排行