php 守护进程
2017-12-15 本文已影响86人
aoshi
php扩展需求
php-pcntl
php-posix
守护进程实现代码
Class Daemon{
/**
* 初始化一个守护进程
* @throws Exception
*/
public function init(){
//创建一个子进程
$pid = pcntl_fork();
if ($pid == -1) {
throw new Exception('fork子进程失败');
} elseif ($pid > 0) {
//父进程退出,子进程变成孤儿进程被1号进程收养,进程脱离终端
exit(0);
}
//创建一个新的会话,脱离终端控制,更改子进程为组长进程
$sid = posix_setsid();
if ($sid == -1) {
throw new Exception('setsid fail');
}
//修改当前进程的工作目录,由于子进程会继承父进程的工作目录,修改工作目录以释放对父进程工作目录的占用。
chdir('/');
/**
* 通过上一步,我们创建了一个新的会话组长,进程组长,且脱离了终端,但是会话组长可以申请重新打开一个终端,为了避免
* 这种情况,我们再次创建一个子进程,并退出当前进程,这样运行的进程就不再是会话组长。
*/
$pid = pcntl_fork();
if ($pid == -1) {
throw new Exception('fork子进程失败');
} elseif ($pid > 0) {
//再一次退出父进程,子进程成为最终的守护进程
exit(0);
}
//由于守护进程用不到标准输入输出,关闭标准输入,输出,错误输出描述符
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
}
}
实例化一个守护进程
$daemon = new Daemon();
$daemon->init();
针对需求进行分析:
需求:有一个常驻队列messageQueue(假设在redis内存中),这个队列会有可能有请求不定期的往队列中增加元素。同时我们要求在队列中有元素的时候,按照队列顺序将元素pop出来,并进行处理(假设这个处理只是echo ‘test’);
解决方法:
现在假设已经有了两个函数
function oPopMessageQueue(){ …} //获取队列最后一个元素;
function vDealElement($element) { …} 处理元素;
要求写出一个守护程序,完成上面的需求。
好了,这个程序很容易想到,可以使用while循环来做
程序:
while(true)
{
if( $element = oPopMessageQueue())
{
vDealElement($element);
}
}
考虑1 : 这个程序如果一直跑的话已经可以满足上面的需求了.
但是考虑到:1 用php进程跑有可能会由于各种情况(比如运行时间过长),Cpu使用率达到100%,进程挂了,这样程序就无法自动重连了.
方法:使用cron
我们在定时脚本中每10分钟起一个进程跑这个程序。
然后设置这个程序的运行时间为10分钟,10分钟后自动取消,于是代码变成
$timeStart = time(); //设置开始值
while(true) {
//有设置开始值
if(empty($timeStart)) {
$timeStart = time();
}
$diffTime = time() - $timeStart; //计算进程时间差
if($diffTime > 600) { //时间超过5秒
exit; //终止运行
}
}
考虑2,可能会有这种需求: 需要有随时让脚本暂停的功能:
于是考虑使用文件或者缓存来增加暂停功能
方法1: 让程序终止执行,有需要的时候再次启动进程
while(true) {
if(file_exists("/home/daemon/stop")) //判断终止文件是否存在
{
exit;
}
}
方法2:让程序睡眠指定秒数
while(true) {
if(file_exists("/home/daemon/sleep")) //判断终止文件是否存在
{
$second = file_get_contents("/home/daemon/sleep");
$second = (int)$second;
if($second) { //让程序睡眠指定秒数
sleep($second);
}
}
}
考虑3, 是否可以改成多线程的程序,让运行的效率更高?
这个只要把cron的10分钟起一个进程的限制改成每1分钟起一个进程就好了
这样能保证有10个线程在运行程序
但是有一个基本要求是:oPopMessageQueue()是一个原子操作(整个逻辑处理成功才算成功,有一个失败就需要回滚<事务>)
出处:http://www.cnblogs.com/yjf512/
本文版权归yjf512和cnBlog共有,欢迎转载,但未经作者同意必须保留此段声明