|
先说一下我的需求:服务器产生一个常驻进程,此进程用来运行我们的php脚本,在脚本中我们会用到pcntl系列方法,而且我们希望每次fork N个子进程,多余的子进程放进一个队列里(数组队列),当N个子进程运行结束的时候在运行队列中的N个子进程,以此类推,直到全部进程结束.
下面是我们官方手册上找的一个NB的列子,顺便写上我做的注释(可能翻译的很狗血),我先把自己不懂得提出来
1:脚本开始就用declare(ticks=1); 目的何为,(google了一下,发现说的都很模糊,英文又看不懂,我哭了...),注释了后程序一直处于等待状态算是一个死循环吧.
2:出现的两个sleep(),其中一个或者全部注释后程序运行和情况一相同,为什么sleep后(或者sleep时)程序貌似进入另一种循环状态(这点我说不清楚,因为我看不出来他是怎么调用launchJob方法或者是run方法)
3:这个程序没有执行childSignalHandler这个方法,那他是如何解决N个子进程结束后在执行另外N个子进程
4:请大牛把这个例子的执行流程清晰的写下来(万分感谢啊{:soso_e105:}),并把关键点和需要额外补充的知识点说一下(还是万分感谢啊{:soso_e105:})
PHP复制代码
<?php
/**
* Using pcntl_fork() can be a little tricky in some situations. For fast jobs, a child can finish processing before the parent process has executed some code related to
* the launching of the process. The parent can receive a signal before it's ready to handle the child process' status. To handle this scenario, I add an id to a
* "queue" of processes in the signal handler that need to be cleaned up if the parent process is not yet ready to handle them.
* I am including a stripped down version of a job daemon that should get a person on the right track.
*
* @author Sammy Guergachi <sguergachi at gmail.com>
*/
declare(ticks =1);
//A very basic job daemon that you can extend to your needs.
class JobDaemon {
public $maxProcesses = 2;
protected $jobsStarted = 0;
protected $currentJobs = array();
protected $signalQueue=array();
protected $parentPID;
public function __construct (){
echo "constructed \n";
$this->parentPID = getmypid();
pcntl_signal (SIGCHLD , array($this, "childSignalHandler"));
}
/**
* Run the Daemon
* 运行守护进程
*/
public function run (){
echo "Running \n";
for($i=0; $i<10; $i++){
$jobID = rand(0,10000000000000);
while(count($this->currentJobs) >= $this->maxProcesses){
echo "Maximum children allowed, waiting...\n";
sleep(1);
}
$launched = $this->launchJob($jobID);
}
//Wait for child processes to finish before exiting here
//等待子进程完成之前离开这里
while(count($this->currentJobs)){
echo "Waiting for current jobs to finish... \n";
sleep(1);
}
}
/**
* Launch a job from the job queue
* 从作业(任务)队列启动工作
*/
protected function launchJob ($jobID){
//创建子进程
$pid = pcntl_fork ();
if($pid == -1){
//Problem launching the job
//启动作业出问题了
error_log('Could not launch new job, exiting');
return false;
}else if ($pid){
// Parent process
// Sometimes you can receive a signal to the childSignalHandler function before this code executes if
// the child script executes quickly enough!
// 父进程
//如果子脚本执行不够快.在代码执行前,有时候你会从childSignalHandler函数中接收一个信号
$this->currentJobs[$pid] = $jobID;
// In the event that a signal for this pid was caught before we get here, it will be in our signalQueue array
// So let's go ahead and process it now as if we'd just received the signal
//在这个pid的信号被捕捉之前我们到达,它将在我们signalQueue数组中
//因此让我们继续前进并处理他,如果我们刚刚收到信号
if(isset($this->signalQueue[$pid])){
echo "found $pid in the signal queue, processing it now \n";
$this->childSignalHandler(SIGCHLD , $pid, $this->signalQueue[$pid]);
unset($this->signalQueue[$pid]);
}
}else{
//Forked child, do your deeds....
//forked的子进程,做你想做的
$exitStatus = 0; //Error code if you need to or whatever 如果你需要或任何的错误代码
echo "Doing something fun in pid ".getmypid()."\n";
exit($exitStatus);
}
return true;
}
public function childSignalHandler ($signo, $pid=null, $status=null){
//If no pid is provided, that means we're getting the signal from the system. Let's figure out
//which child process ended
//如果没有pid被提供,这意味着我们从系统得到信号,让我们弄清楚哪个子进程结束了
if(!$pid){
//等待或返回fork的子进程状态
$pid = pcntl_waitpid (-1, $status, WNOHANG );
}
//Make sure we get all of the exited children
//确保我们得到所有已退出的子进程
while($pid > 0){
if($pid && isset($this->currentJobs[$pid])){
//返回一个中断的子进程的返回代码
$exitCode = pcntl_wexitstatus ($status);
if($exitCode != 0){
echo "$pid exited with status ".$exitCode."\n";
}
unset($this->currentJobs[$pid]);
}
else if($pid){
//Oh no, our job has finished before this parent process could even note that it had been launched!
//Let's make note of it and handle it when the parent process is ready for it
//我们的工作已完成,在此之前的父进程甚至可能会注意到,它已启动!
//注意,当父进程准备好时处理它
echo "..... Adding $pid to the signal queue ..... \n";
$this->signalQueue[$pid] = $status;
}
$pid = pcntl_waitpid (-1, $status, WNOHANG );
}
return true;
}
}
$daemon = new JobDaemon ();
$daemon -> run();
?>
复制代码
原例子:http://www.php.net/manual/en/function.pcntl-fork.php#98711
|
|