在使用php-resque队列时使用到PHP进程的相关内容总结

好文章:
http://www.jianshu.com/p/08bcf724196b
http://www.jb51.net/article/71232.htm
https://www.pureweber.com/article/php-multi-process-programming-preview/
http://rainyluo.net/post/php_mutilcurl

问题:多进程执行任务的方法
子进程执行任务,如何返回消息给父进程
父进程阻塞模式,非阻塞模式
父进程,子进程挂掉怎么处理

多进程优点:

  1. 使用多进程。子进程结束,内核负责回收资源。
  2. 使用多进程,子进程异常退出不会导致整个进程Thread退出,父进程还有机会重建流程
    via鸟哥的博客:http://www.laruence.com/2009/06/11/930.html
    守护进程: 主要的方法
    下方文章来源:https://www.pureweber.com/article/php-multi-process-programming-preview/
这个代码只能跑单进程,然后fork值fork出一个子进程,其实可以多fork几个出来。如果想实现多进程php-resque本身初始化的时候需要指定  COUNT= 值
	public function work($interval = 5)
	{
		$this->updateProcLine('Starting');
		$this->startup();

		while(true) {
			if($this->shutdown) {
				break;
			}

			// Attempt to find and reserve a job
			$job = false;
			if(!$this->paused) {
				$job = $this->reserve();
			}

			if(!$job) {
				// For an interval of 0, break now - helps with unit testing etc
				if($interval == 0) {
					break;
				}
				// If no job was found, we sleep for $interval before continuing and checking again
				$this->log('Sleeping for ' . $interval, true);
				if($this->paused) {
					$this->updateProcLine('Paused');
				}
				else {
					$this->updateProcLine('Waiting for ' . implode(',', $this->queues));
				}
				usleep($interval * 1000000);
				continue;
			}

			$this->log('got ' . $job);
			Resque_Event::trigger('beforeFork', $job);
			$this->workingOn($job);

			$this->child = $this->fork();

			// Forked and we're the child. Run the job.
			if ($this->child === 0 || $this->child === false) {
				$status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T');
				$this->updateProcLine($status);
				$this->log($status, self::LOG_VERBOSE);
				$this->perform($job);
				if ($this->child === 0) {
					exit(0);
				}
			}

			if($this->child > 0) {
				// Parent process, sit and wait
				$status = 'Forked ' . $this->child . ' at ' . strftime('%F %T');
				$this->updateProcLine($status);
				$this->log($status, self::LOG_VERBOSE);

				// Wait until the child process finishes before continuing
				pcntl_wait($status);
				$exitStatus = pcntl_wexitstatus($status);
				if($exitStatus !== 0) {
					$job->fail(new Resque_Job_DirtyExitException(
						'Job exited with exit code ' . $exitStatus
					));
				}
			}

			$this->child = null;
			$this->doneWorking();
		}

		$this->unregisterWorker();
	}
$parentPid = getmypid(); // 这就是传说中16岁之前的记忆
$pid = pcntl_fork(); // 一旦调用成功,事情就变得有些不同了   $pid 为子进程Id和0

0为子进程, >0 位子进程ID??  //不知道怎么描述这句话、、反正执行的结果如下

if ($pid == -1) {
    die('fork failed');
} else if ($pid == 0) {
    $mypid = getmypid(); // 用getmypid()函数获取当前进程的PID
    echo 'I am child process. My PID is ' . $mypid . ' and my father's PID is ' . $parentPid . PHP_EOL;
} else {
    echo 'Oh my god! I am a father now! My child's PID is ' . $pid . ' and mine is ' . $parentPid . PHP_EOL;
}
输出
I am child process. My PID is 6065 and my fathers PID is 6064
Oh my god! I am a father now! My childs PID is 6065 and mine is 6064

这里如果在父进程和子进程中都sellp(10); 可以查看到两个进程 6064 和 6065
这里写图片描述

再强调一下,pcntl_fork()调用成功以后,一个程序变成了两个程序:一个程序得到的 p i d 变 量 值 是 0 , 它 是 子 进 程 ; 另 一 个 程 序 得 到 的 pid变量值是0,它是子进程;另一个程序得到的 pid0pid的值大于0,这个值是子进程的PID,它是父进程。在下面的分支语句中,由于$pid值的不同,运行了不同的代码。再次强调一下:子进程的代码和父进程的是一样的。所以就要通过分支语句给他们分配不同的任务。

一般来说,在父进程结束之前回收挂掉的子进程就可以了。在pcntl扩展里面有一个pcntl_wait()函数,它会将父进程挂起,直到有一个子进程退出为止。如果有一个子进程变成了僵尸的话,它会立即返回。所有的子进程都要回收,所以多等等也没关系啦!

父进程先挂了
如果父进程先挂了怎么办?会发生什么?什么也不会发生,子进程依旧还在运行。但是这个时候,子进程会被交给1号进程,1号进程成为了这些子进程的继父。1号进程会很好地处理这些进程的资源,当它们结束时1号进程会自动回收资源。所以,另一种处理僵尸进程的临时办法是关闭它们的父进程

// 定义一个处理器,接收到SIGINT信号后只输出一行信息
function signalHandler($signal) {
    if ($signal == SIGINT) {
        echo 'signal received' . PHP_EOL;
    }
}
// 信号注册:当接收到SIGINT信号时,调用signalHandler()函数
pcntl_signal(SIGINT, 'signalHandler');
while (true) {
    sleep(1);
    // do something
    pcntl_signal_dispatch(); // 接收到信号时,调用注册的signalHandler()
}

关于函数方法:

getmygid() - 获取当前 PHP 脚本拥有者的 GID
getmyuid() - 获取 PHP 脚本所有者的 UID
get_current_user() - 获取当前 PHP 脚本所有者名称
getmyinode() - 获取当前脚本的索引节点(inode)
getlastmod() - 获取页面最后修改的时间
posix_getpid()   返回当前进程 id

pcntl_fork()  	pcntl_fork()函数成功执行时会在父进程返回子进程的进程id(pid),因为系统的初始进程init进程的pid为1,后来产生进程的pid都会大于此进程,所以我们可以通过判断pcntl_fork()的返回值大于1来确实当前进程是父进程;而在子进程中,此函数的返回值会是固定值0,我们也可以通过判断pcntl_fork()的返回值为0来确定子进程;

posix_kill() bool posix_kill ( int $pid , int $sig ) // 向进程id为$pid的进程发送$sig信号,

pcntl_waitpid(-1, $status, WNOHANG) $status

pcntl_signal (int $signo , callback $handler) 安装一个信号处理器;
			$signo是待处理的信号常量,callback是其处理函数

pcntl_wait() 父进程在pcntl_wait()将自己阻塞,等待子进程运行完了才接着运行。

int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )  // 挂起当前进程的执行直到进程号为$pid的进程退出(如果$pid为-1,则等待任意一个子进程); 

PHP内常见的信号常量有:			
SIGCHLD     子进程退出成为僵尸进程会向父进程发送此信号
SIGHUP      进程挂起
SIGTEM      进程终止
...         // 其他请在手册中查看



pcntl_signal_dispatch () 调用每个等待信号通过pcntl_signal()安装的处理器


这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值