PHP多进程系列笔记(二)

上一篇文章讲解了 和 两个函数的使用,本篇继续讲解PHP多进程相关新知识。

僵尸(zombie)进程

这里说下僵尸进程:

僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程。任何进程在退出前(使用exit退出) 都会变成僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多,最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。

通过如下命令查看是否有僵尸进程,如果有,类似下面这样:

如果子进程还没有结束时,父进程就结束了,那么init进程会自动接手这个子进程,进行回收。

如果父进程是循环,又没有安装 信号处理函数调用 或 等待子进程结束。那么子进程结束后,没有回收,就产生僵尸进程了。

示例: fork_zombie.php

命令行里运行程序,然后新终端查看:

出现了一个僵尸进程。这时候就算手动结束脚本程序也无法关闭这个僵尸子进程了。需要使用 关闭。

pcntl_signal

该函数为 指定的信号安装一个新的信号处理器。

安装SIGCHLD信号

上一节里,我们讲到僵尸进程产生的原因:

如果父进程是循环,又没有安装 信号处理函数调用 或 等待子进程结束。那么子进程结束后,没有回收,就产生僵尸进程了。

本小节我们通过安装SIGCHLD信号处理函数来解决僵尸进程问题。示例:

第一次注释掉 和 处的代码,父进程提前结束,子进程被init进程接手,所以没有产生僵尸进程。 第二次我们注释掉 处的代码,开启 处的代码,即父进程是个死循环,又没有回收子进程,就产生僵尸进程了。 第三次我们开启 处和 处的代码,父进程由于安装了信号处理,并调用wait函数等待子进程结束,所以也没有产生僵尸进程。

对子进程的结束不感兴趣如果父进程不关心子进程什么时候结束,那么可以用 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号。这样我们就不写子进程退出的处理函数了。

说明:

如果去掉 无法响应信号。因php的信号处理函数是基于ticks来实现的,而不是注册到真正系统底层的信号处理函数中。

安装其他信号

我们可以在主进程安装更多信号,例如:

注:通过 可以看到Linux下所有的信号常量。

防盗版声明:本文系原创文章,发布于公众号 及博客园,转载需作者同意。

ticks相关

PHP的 表示每执行1行PHP代码就回调此函数(指的 )。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。如果一个服务器程序1秒中接收1000次请求,平均每个请求要执行1000行PHP代码。那么PHP的pcntlsignal,就带来了额外的 1000 * 1000,也就是100万次空的函数调用。这样会浪费大量的CPU资源。 (摘自:韩天峰(Rango)的博客 » PHP官方的pcntlsignal性能极差 http://rango.swoole.com/archives/364)

pcntlsignaldispatch的作用就是查看是否收到了信号需要处理,如果有信号的话,就调用相应的信号处理函数。

所以上述问题比较好的做法是去掉ticks,转而手动调用 ,在代码循环中自行处理信号。

我们把上一小节的例子改改,不使用ticks:

运行结果:

相比每执行一条php语句都会调用 一次,效率好多了。

pcntl_alarm

该函数创建一个计时器,在指定的秒数后向进程发送一个 信号。每次对 的调用都会取消之前设置的alarm信号。注意不是定时器,只会运行一次。

下面是一个隔5秒发送一个SIGALRM信号,并由signal_handler函数获取,然后打印一个 的例子:

注:如果不想使用ticks,那么需要在主循环里主动增加 调用。

(未完待续)

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180619G06XKJ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券