多进程应用背景
说起多进程,大家肯定不陌生,但是说起php的多进程,可能一些做php的同学就有点不太明白了,因为我们平常在开发php程序的时候,大部分都是开发的web程序,而web程序往往用不到多进程方式。
但是有这样一种场景:php脚本处理大量数据,量那是相当的大,单词执行要跑十多个小时,这个时候多进程就派上用场了。
php如何使用多进程
php的多进程需要依赖扩展,这个扩展的名字叫做:pcntl,如何安装扩展这里就不必要进行多说了,自行百度,给个这个扩展的传送门:pcntl扩展官方说明
安装完这个扩展,其中有一个函数: pcntl_fork,这个函数就是在这行之后进行fork一个子进程,注意是从fork之后那行之后开始执行的,给个栗子吧。
执行结果:
可以看出来fork之前的主进程内容只执行一次。
下面再说pcntl_fork所返回的pid,这个pid有可能是有三种情况:
1. 如果fork出错,比如系统分配不了进程数等,返回-1。
2. fork成功,pid大于0的时候,是主进程。
3. fork成功,pid等于0的时候,是子进程。
经过以上的例子就可以知道对于php,如何进行多进程操作了。
主进程、子进程死掉之后会发生啥
场景:一个主进程,fork了一个子进程,一共会发生以下几种情况:
1. 都存活:这个就不用多说了,相安无事;
2. 主进程挂掉,子进程存活: 这样这个子进程就变成了 孤儿进程,孤儿进程将被init进程(进程号为1)的进程收养,并由init进程对他们进行完成状态收集工作。
3. 子进程挂掉,主进程存活:如果子进程挂掉,主进程没有调用wait或者waitpid方法,那么进程就会保留在系统中,仍然占用着资源,这种进程叫做 僵尸进程。
4. 都死掉:也可以,只要完成了相关状态收集以及回收工作就ok。
如何防止僵尸进程
对于刚才所讲的僵尸进程,需要做的事情就是,在主进程中一定要调用wait或者waitpid方法,
pcntl_wait的传送门:pcntl_wait
pcntl_waitpid的传送门:pcntl_waitpid
这两个函数有一个很大的作用,就是我可以通过主进程关注到子进程是否还存活,如果子进程被kill了是可以获取到状态的。其中有个场景会用到:
我开启了多个进程,每个进程里面可能会抛出exception,或者出现一些fatal error,那么这个子进程就挂掉了,这时候就可以通过这样的方式进行重启,直接上代码:
这里面就可以进行实现子进程出现exception的时候自动重启一个进程。
如何通过fork实现守护进程
普通的php守护进程可以通过nohup进行实现,但是这种方法是不是太low了。
下面介绍一下通过fork实现php守护进程的方式,原理很简单:上来先fork一个子进程,然后把父进程exit掉,这样子进程变成了孤儿进程,被init进程接管,就实现了守护进程。
上代码:
这其中用到posix_setsid这个函数,传送门:posix_setid
多进程的注意事项
多进程只能在cli模式进行使用,fpm你是别想了。
多进程一定要在主进程调用wait或者waitpid
守护进程据说SVR4内核的linux系统要fork两次,因为可能第一次会被拒绝,这个有待验证。
github上有一些基于fork的多进程封装,如ko_process,恩,你的hold住,这个封装有个共享内存的问题,启动多次会出现问题,能解决即可。