PHP多进程编程实例说明

子进度的创始常常的子进度的写法是:

PHP有一组经过调整函数(编写翻译时索要
–enable-pcntl与posix扩大卡塔尔国,使得php能在*nix系统中贯彻跟c同样的成立子进度、使用exec函数实践顺序、管理功率信号等效用。
PCNTL使用ticks来作为随机信号管理机制(signal handle callback
mechanism),能够一点都不大程度地下落管理异步事件时的负载。何谓ticks?Tick
是一个在代码段中解释器每实践 N
条低端语句就能够时有发生的风云,那么些代码段需求经过declare来钦命。

php$pid = pcntl_fork();if($pid == -1){ //创建失败 die('could not fork');}else{ if($pid){ //从这里开始写的代码是父进程的 exit("parent!"); } else{ //子进程代码,为防止不停的启用子进程造成系统资源被耗尽的情况,一般子进程代码运行完成后,加入exit来确保子进程正常退出。 exit("child"); }}

常用的PCNTL函数

上面包车型客车代码就算创设子进度成功的话,系统就有了2个进度,贰个为父进度,一个为子进程,子进度的id号为$pid。在系统运行到$pid

pcntl_fork(State of Qatar;时,在那个地点开展分层,老爹和儿子进度各自开端运营各自的程序代码。代码的周转结果是parent
和child,很想得到啊,为啥二个if和else互斥的代码中,都输出了结果?其实是像上边所说的,代码在pcntl_fork时,多少个父进程运维parent,贰个子历程运转了child。在代码结果上就显得了parent和child。至于哪个人先哪个人后的难点,那得要看系统能源的分配了。

只要急需起三个经过来拍卖数据,能够根据数量的多寡,根据约定好的多寡例如说1000条二个进程来起子进度。使用for循环就可以了。

 #如果获得的总数小于或等于0,等待60秒,并退出 if ($count = 0) { sleep(60); exit; } #如果大于1000,计算需要起的进程数 if ($count  1000) { $cycleSize = ceil($count/1000); } else { $cycleSize = 1; } for ($i=0; $i$cycleSize; $i++) { $pid = pcntl_fork(); if($pid == -1) { break; } else { if($pid) { #父进程获得子进程的pid,存入数组 $pidArr[] = $pid; } else { //开始发送,子进程执行完自己的任务后,退出。 exit; } } } while(count($pidArr)  0) { $myId = pcntl_waitpid(-1, $status, WNOHANG); foreach($pidArr as $key = $pid) { if($myId == $pid) unset($pidArr[$key]); } }

接下来利用crontab,来使此PHP程序每间距一段时间自动推行。

当然,示例代码比较容易,具体还索要思忖怎么防范八个子进度推行到平等条数据或许当前历程管理数量未成功时,crontab又起来实践PHP文件启用新的进程等等。

PHP多进度完毕情势下边来系统地收拾一下PHP多进度的贯彻方式:

1. 直接格局

pcntl_fork(卡塔尔(قطر‎创造一个过程,在父进度重临值是子进程的pid,在子进度再次回到值是0,-1代表创造进度受挫。跟C特别相仿。

测量试验脚本 test.php

php // example of multiple processes date_default_timezone_set( 'Asia/Chongqing'); echo "parent start, pid ", getmypid(), "/n" ; beep(); for ($i=0; $i3; ++$i){ $pid = pcntl_fork(); if ($pid == -1){ die ("cannot fork" ); } else if ($pid  0){ echo "parent continue /n"; for ($k=0; $k2; ++$k){ beep(); } } else if ($pid == 0){ echo "child start, pid ", getmypid(), "/n" ; for ($j=0; $j5; ++$j){ beep(); } exit ; } } // *** function beep(){ echo getmypid(), "/t" , date( 'Y-m-d H:i:s', time()), "/n" ; sleep(1); }

用命令行运维

#php -f test.php

出口结果

parent start, pid 17931793 2013-01-14 15:04:17parent continue1793 2013-01-14 15:04:18child start, pid 17941794 2013-01-14 15:04:181794 2013-01-14 15:04:191793 2013-01-14 15:04:191794 2013-01-14 15:04:20parent continue1793 2013-01-14 15:04:20child start, pid 17951795 2013-01-14 15:04:2017931794 2013-01-14 15:04:212013-01-14 15:04:211795 2013-01-14 15:04:211794 2013-01-14 15:04:221795 2013-01-14 15:04:22parent continue1793 2013-01-14 15:04:22child start, pid 17961796 2013-01-14 15:04:221793 2013-01-14 15:04:231796 2013-01-14 15:04:231795 2013-01-14 15:04:231795 2013-01-14 15:04:241796 2013-01-14 15:04:241796 2013-01-14 15:04:251796 2013-01-14 15:04:26

从当中看见,创立了3个子进度,和父进度一同互相运营。在那之中有一行格式跟其余有些不一致,17931794
二零一三-01-14 15:04:212012-01-14
15:04:21因为七个经过相同的时间举办写操作,形成了冲突。

2. 堵塞格局

用直白情势,父进度创设了子进度后,并不曾等待子进度停止,而是继续运营。就像是这里看不到有哪些难点。假诺php脚本实际不是运作完后自行终止,而是常驻内部存款和储蓄器的,就能够形成子进度无法回收的难点。也正是活死人进度。能够经过pcntl_wai(State of Qatar方法等待历程结束,然后回笼已经终止的进度。将测量试验脚本改成:

$pid = pcntl_fork();if ($pid == -1){ ...} else if ($pid  0){ echo "parent continue /n"; pcntl_wait($status); for ($k=0; $k2; ++$k){ beep(); }} else if ($pid == 0){ ...}

用命令行运维

#php -f test.php

输出结果

parent start, pid 18071807 2013-01-14 15:20:05parent continuechild start, pid 18081808 2013-01-14 15:20:061808 2013-01-14 15:20:071808 2013-01-14 15:20:081808 2013-01-14 15:20:091808 2013-01-14 15:20:101807 2013-01-14 15:20:111807 2013-01-14 15:20:12parent continuechild start, pid 18091809 2013-01-14 15:20:131809 2013-01-14 15:20:141809 2013-01-14 15:20:151809 2013-01-14 15:20:161809 2013-01-14 15:20:171807 2013-01-14 15:20:181807 2013-01-14 15:20:19child start, pid 18101810 2013-01-14 15:20:20parent continue1810 2013-01-14 15:20:211810 2013-01-14 15:20:221810 2013-01-14 15:20:231810 2013-01-14 15:20:241807 2013-01-14 15:20:251807 2013-01-14 15:20:26

父进程在pcntl_wait(State of Qatar将团结过不去,等待子进度运营完了才跟着运转。

3. 非围堵格局

拥塞方式失去了多进程的并行性。还应该有一种办法,不仅可以够回收已经完工的子进程,又足以并行。那正是非梗塞的章程。更改脚本:

php // example of multiple processes date_default_timezone_set( 'Asia/Chongqing'); declare (ticks = 1); pcntl_signal(SIGCHLD, "garbage" ); echo "parent start, pid ", getmypid(), "/n" ; beep(); for ($i=0; $i3; ++$i){ $pid = pcntl_fork(); if ($pid == -1){ die ("cannot fork" ); } else if ($pid  0){ echo "parent continue /n"; for ($k=0; $k2; ++$k){ beep(); } } else if ($pid == 0){ echo "child start, pid ", getmypid(), "/n" ; for ($j=0; $j5; ++$j){ beep(); } exit (0); } } // parent while (1){ // do something else sleep(5); } // *** function garbage($signal){ echo "signel $signal received/n" ; while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) 0){ echo "/t child end pid $pid , status $status/n" ; } } function beep(){ echo getmypid(), "/t" , date( 'Y-m-d H:i:s', time()), "/n" ; sleep(1); }

用命令行运营

#php -f test.php &

输出结果

parent start, pid 20662066 2013-01-14 16:45:34parent continue2066 2013-01-14 16:45:35child start, pid 20672067 2013-01-14 16:45:3520662067 2013-01-14 16:45:362013-01-14 16:45:362067 2013-01-14 16:45:37parent continue2066 2013-01-14 16:45:37child start, pid 20682068 2013-01-14 16:45:372067 2013-01-14 16:45:382068 2013-01-14 16:45:382066 2013-01-14 16:45:38parent continue2066 2013-01-14 16:45:40child start, pid 20692069 2067 2013-01-14 16:45:402013-01-14 16:45:402068 2013-01-14 16:45:402066 2013-01-14 16:45:412069 2013-01-14 16:45:412068 2013-01-14 16:45:41signel 17 received child end pid 2067, status 02069 2013-01-14 16:45:422068 2013-01-14 16:45:422069 2013-01-14 16:45:43signel 17 received child end pid 2068, status 02069 2013-01-14 16:45:44signel 17 received child end pid 2069, status 0

八个进程又相互运转了,况兼运转差不离10秒钟之后,用 ps -ef | grep php
查看正在运营的长河,独有一个经过lqling 2066 1388 0 16:45 pts/1 00:00:00
php -f t5.php是父进度,子进度被回笼了。

子进程退出状态

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

重临子过程的终止状态

windows下三十二线程

windows系统不支持pcntl函数,幸而有curl_multi_exec(卡塔尔这一个工具,利用内部的八线程,访问三个链接,各种链接能够看做一个职务。

编写脚本 test1.php

php date_default_timezone_set( 'Asia/Chongqing'); $tasks = array( '', '', '' ); $mh = curl_multi_init(); foreach ($tasks as $i = $task){ $ch[$i] = curl_init(); curl_setopt($ch[$i], CURLOPT_URL, $task); curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1); curl_multi_add_handle($mh, $ch[$i]); } do {$mrc = curl_multi_exec($mh,$active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select($mh) != -1) { do {$mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } // completed, checkout result foreach ($tasks as $j = $task){ if (curl_error($ch[$j])){ echo "task ${j} [$task ] error " , curl_error($ch[$j]), "/r/n" ; } else { echo "task ${j} [$task ] get: /r/n" , curl_multi_getcontent($ch[$j]), "/r/n" ; } }

编排脚本 test2.php

php date_default_timezone_set( 'Asia/Chongqing'); echo "child start, pid ", getmypid(), "/r/n" ; for ($i=0; $i5; ++$i){ beep(); } exit (0); // *** function beep(){ echo getmypid(), "/t" , date('Y-m-d H:i:s' , time()), "/r/n"; sleep(1); }

用命令行运维

#php -f test1.php &

出口结果

task 0 [] get:child start, pid 58045804 2013-01-15 20:22:355804 2013-01-15 20:22:365804 2013-01-15 20:22:375804 2013-01-15 20:22:385804 2013-01-15 20:22:39task 1 [] get:child start, pid 58045804 2013-01-15 20:22:355804 2013-01-15 20:22:365804 2013-01-15 20:22:375804 2013-01-15 20:22:385804 2013-01-15 20:22:39task 2 [] get:child start, pid 58045804 2013-01-15 20:22:355804 2013-01-15 20:22:365804 2013-01-15 20:22:375804 2013-01-15 20:22:385804 2013-01-15 20:22:39

从打字与印刷的小时拜会,多个职务大概是还要运转的。

   1. pcntl_alarm ( int $seconds )

      设置一个$seconds秒后发送SIGALRM时域信号的流速計
   2. pcntl_signal ( int $signo , callback $handler [, bool
$restart_syscalls ] )

     
为$signo设置八个拍卖该实信号的回调函数。下边是叁个隔5秒发送三个SIGALRM非时限信号,并由signal_handler函数获取,然后打字与印刷一个“Caught
SIGALRM”的例证:
declare(ticks = 1);

function signal_handler($signal) {
print “Caught SIGALRMn”;
pcntl_alarm(5);
}

pcntl_signal(SIGALRM, “signal_handler”, true);
pcntl_alarm(5);

for(;;) {
}

?>

   3. pcntl_exec ( string $path [, array $args [, array $envs ]] )

     
在近期的进度空间中实践钦定程序,相似于c中的exec族函数。所谓当前空间,即载入内定程序的代码覆盖掉当前经过的半空中,实施完该程序进度即甘休。
$dir = ‘/home/shankka/’;
$cmd = ‘ls’;
$option = ‘-l’;
$pathtobin = ‘/bin/ls’;

$arg = array($cmd, $option, $dir);

pcntl_exec($pathtobin, $arg);
echo ‘123’; //不会履行到该行
?>

   4. pcntl_fork ( void )

     
为当前经过创立二个子经过,並且先运维父进度,重返的是子进度的PID,确定不仅零。在父进度的代码中能够用
pcntl_wait(&$status)暂停父进程知道他的子进程有重临值。注意:父进度的隔断同一时间会拥塞子进度。可是父进度的扫尾不影响子进度的周转。

     
父进度运转完了会随之运维子进程,这个时候子进度会从奉行pcntl_fork()的那条语句早前实践(包含此函数),但是那时候它回到的是零(代表那是贰个子经过)。在子进度的代码块中最棒有exit语句,即实行完子进程后迅即就与世长辞。不然它会又重头初始执行这些本子的一点部分。

      注意两点:
      1. 子进度最棒有三个exit;语句,幸免不供给的失误;
      2. pcntl_fork间最佳永不有别的语句,比如:
$pid = pcntl_fork();
//这里最棒不要有其它的话语
if ($pid == -1) {
die(‘could not fork’);
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}

   5. pcntl_wait ( int &$status [, int $options ] )

     
堵塞当前行程,只到近些日子经过的二个子过程退出只怕摄取二个完成近年来历程的非模拟信号。使用$status再次回到子进程的状态码,并能够钦定第3个参数来声明是还是不是以堵塞状态调用:
      1.
不通情势调用的,函数再次回到值为子进度的pid,若无子进度重临值为-1;
      2.
非封堵方式调用,函数还足以在有子进度在运作但没有终结的子进度时重返0。
   6. pcntl_waitpid ( int $pid , int &$status [, int $options ] )

     
功能同pcntl_wait,分化为waitpid为等待内定pid的子进度。当pid为-1时pcntl_waitpid与pcntl_wait
一样。在pcntl_wait和pcntl_waitpid七个函数中的$status中存了子进度的情况音讯,这一个参数能够用于
pcntl_wifexited、pcntl_wifstopped、pcntl_wifsignaled、pcntl_wexitstatus、
pcntl_wtermsig、pcntl_wstopsig、pcntl_waitpid这几个函数。

      例如:

       $pid = pcntl_fork();
if($pid) {
pcntl_wait($status);
$id = getmypid();
echo “parent process,pid {$id}, child pid {$pid}n”;
}else{
$id = getmypid();
echo “child process,pid {$id}n”;
sleep(2);
}
?>

      子进度在出口child
process等字样之后sleep了2秒才截止,而父进度梗塞着直到子进度退出之后才继续运维。
   7. pcntl_getpriority ([ int $pid [, int $process_identifier ]]
)

     
获得进程的优先级,即nice值,默以为0,在自个儿的测量检验情状的linux中(CentOS
release 5.2
(FinalState of Qatar),优先级为-20到19,-20为优先级最高,19为压低。(手册中为-20到20)。
   8. pcntl_setpriority ( int $priority [澳门新葡亰娱乐官网 ,, int $pid [, int
$process_identifier ]] )

      设置进程的早期级。
   9. posix_kill

      能够给进度发送连续信号
  10. pcntl_singal

      用来安装非随机信号的回调函数

当父进程退出时,子进程如何识破父进度的淡出
当父进度退出时,子进度日常能够透过上边那五个比较简单的措施得悉父进度早就退出这几个音信:

   1.
当父进程退出时,会有多个INIT进度来领养那些子进度。那一个INIT进程的进程号为1,所以子进度能够透过动用getppid(卡塔尔来取安妥前父进度的pid。假设回去的是1,声明父进程早就改成INIT进程,则原经过一度推出。
   2. 施用kill函数,向原有的父进度发送空能量信号(kill(pid,
0卡塔尔(قطر‎)。使用这一个方法对有些进程的存在性举办检查,而不会真的发送信号。所以,假使这一个函数再次回到-1代表父进度已经脱离。

除开上边的那三个主意外,还会有一点点实现上相比复杂的方法,举个例子创造管道或socket来实行任何时候的监督检查等等。

PHP多进程搜集数据的例子

/**
* Project: Signfork: php三十四线程库
* File: Signfork.class.php
*/

class Signfork{
/**
* 设置子进度通讯文件所在目录
* @var string
*/
private $tmp_path=’/tmp/’;

/**
* Signfork引擎主运行方法
*
1、决断$arg类型,类型为数组时将值传递给各个子进程;类型为数值型时,代表要成立的进度数.
* @param object $obj 试行对象
* @param string|array $arg 用于对象中的__fork方法所推行的参数
*
如:$arg,自动解释为:$obj->__fork($arg[0])、$obj->__fork($arg[1])…
* @return array 重临 array(子进程种类=>子进度实践结果);
*/
public function run($obj,$arg=1){
if(!method_exists($obj,’__fork’)){
exit(“Method ‘__fork’ not found!”);
}

if(is_array($arg)){
$i=0;
foreach($arg as
$key=>$val){
$spawns[$i]=$key;
$i++;
$this->spawn($obj,$key,$val);
}
$spawns[‘total’]=$i;
}elseif($spawns=intval($arg)){
for($i = 0; $i < $spawns; $i++){
$this->spawn($obj,$i);
}
}else{
exit(‘Bad argument!’);
}

if($i>1000) exit(‘Too many spawns!’);
return
$this->request($spawns);
}

/**
* Signfork主进度调节方式
* 1、$tmpfile
判定子进程文件是还是不是留存,存在则子进度试行达成,并读取内容
* 2、$data搜罗子进度运转结果及数量,并用以最终回到
* 3、删除子进程文件
* 4、轮询叁遍0.03秒,直到全体子进度施行完成,清理子进度财富
* @param string|array $arg 用于对应每种子进程的ID
* @return array 返回 array([子进度类别]=>[子进程实践结果]);
*/
private function request($spawns){
$data=array();
$i=is_array($spawns)?$spawns[‘total’]:$spawns;
for($ids = 0; $ids<$i; $ids++){
while(!($cid=pcntl_waitpid(-1, $status, WNOHANG)))usleep(30000);
$tmpfile=$this->tmp_path.’sfpid_’.$cid;
$data[$spawns[‘total’]?$spawns[$ids]:$ids]=file_get_contents($tmpfile);
unlink($tmpfile);
}
return $data;
}

/**
* Signfork子进程实践形式
* 1、pcntl_fork 生成子进度
* 2、file_put_contents
将’$obj->__fork($val卡塔尔(قطر‎’的试行结果存入特定类别命名的文件
* 3、posix_kill杀死当前经过
* @param object $obj 待实行的靶子
* @param object $i 子进度的队列ID,以便于重回对应每一个子进程数据
* @param object $param 用于输入对象$obj方法’__fork’试行参数
*/
private function spawn($obj,$i,$param=null){
if(pcntl_fork()===0){
$cid=getmypid();
file_put_contents($this->tmp_path.’sfpid_’.$cid,$obj->__fork($param));
posix_kill($cid, SIGTERM);
exit;
}
}
}
?>

php在pcntl_fork(卡塔尔(قطر‎后生成的子过程(平时为活死人进程State of Qatar必得由pcntl_waitpid(State of Qatar函数举办财富自由。但在
pcntl_waitpid(State of Qatar不自然释放的正是当下运转的经过,也说不许是病故生成的活死人进度(未有自由卡塔尔(قطر‎;也大概是并发时其余访谈者的尸鬼进度。但足以应用posix_kill($cid,
SIGTERM卡塔尔国在子进程停止时杀死它。

子进程会自动复制父进程空间里的变量。

PHP多进度编制程序示例2

//…..
//必要安装pcntl的php扩充,并加载它
if(function_exists(“pcntl_fork”)){
//生成子进度
$pid = pcntl_fork();
if($pid == -1){
die(‘could not fork’);
}else{
if($pid){
$status = 0;
//堵塞父进度,直到子进度甘休,不适合须要长日子运作的脚本,可利用pcntl_wait($status,
0卡塔尔国达成非梗塞式
pcntl_wait($status);
// parent proc code
exit;
}else{
// child proc code
//结束方今子进度,以堤防生成丧尸进度
if(function_exists(“posix_kill”)){
posix_kill(getmypid(), SIGTERM);
}else{
system(‘kill -9’. getmypid());
}
exit;
}
}
}else{
// 不支持多进程管理时的代码在这里边
}
//…..
?>

比如不须求梗塞进度,而又想获得子进度的淡出状态,则能够注释掉pcntl_wait($status)语句,或写成:

pcntl_wait($status, 1);
//或
pcntl_wait($status, WNOHANG);

在上面包车型客车代码中,借使父进度退出(使用exit函数退出或redirect卡塔尔,则会引致子进度成为丧尸进度(会付出init进度调控卡塔尔,子进度不再试行。

丧尸进度是指的父进程已经退出,而该进程dead之后未有经过接收,就改为尸鬼进度.(zombie卡塔尔(قطر‎进程。任何进程在退出前(使用exit退出卡塔尔(قطر‎都会产生尸鬼进度(用于保存进程的图景等消息卡塔尔(قطر‎,然后由init进度接管。借使不马上回笼活死人进度,那么它在系统中就能够攻克三个进度表项,要是这种活死人进度过多,最终系统就从未得以用的经过表项,于是也无从再运营此外的前后相继。

防护丧尸进度有以下三种方式:

   1.
父进程经过wait和waitpid等函数使其等待子进程停止,然后再推行父进程中的代码,那会招致父进度挂起。上面包车型客车代码正是利用这种方法得以完成的,但在WEB遭受下,它不符合子进度须要长日子运作的事态(会招致超时卡塔尔(قطر‎。

     
使用wait和waitpid方法使父进度自动回笼其丧尸子进度(遵照子进度的归来状态State of Qatar,waitpid用于临控钦点子进程,wait是对此全部子进度来讲。
   2.
只要父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进度甘休后,父进度会收到该非非确定性信号,能够在handler中调用wait回笼
   3. 万一父进度不关切子进度哪一天截止,那么能够用signal(SIGCHLD,
SIG_IGNState of Qatar布告内核,自身对子进程的收尾不感兴趣,那么子进度截止后,内核会回笼,并不再给父进程发送数字信号,举个例子:

pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
//….code

4.
还应该有几个技术,正是fork若干遍,父进度fork一个子进程,然后继续专业,子进程再fork二个孙进度后退出,那么孙进度被init接管,孙进度甘休后,init会回收。但是子进程的回笼还要和睦做。上边是八个事例:

#include “apue.h”
#include
int main(void){
pid_t pid;

if ((pid = fork()) < 0){
err_sys(“fork error”);
} else if (pid == 0){ /**//* first child */
if ((pid = fork()) < 0){
err_sys(“fork error”);
}elseif(pid > 0){
exit(0); /**//* parent from second fork == first child */
}

/**
* We’re the second child; our parent becomes init as soon
* as our real parent calls exit() in the statement above.
* Here’s where we’d continue executing, knowing that when
* we’re done, init will reap our status.
*/
sleep(2);
printf(“second child, parent pid = %d “, getppid());
exit(0);
}

if (waitpid(pid, NULL, 0) != pid) /**//* wait for first child */
err_sys(“waitpid error”);

/**
* We’re the parent (the original process); we continue executing,
* knowing that we’re not the parent of the second child.
*/
exit(0);
}

     
在fork(卡塔尔(قطر‎/execve(卡塔尔进度中,如果子进度甘休时父进度仍存在,而父进度fork(卡塔尔此前既没设置SIGCHLD实信号处理函数调用
waitpid(卡塔尔(قطر‎等待子进度甘休,又不曾显式忽视该连续信号,则子进度成为尸鬼进程,不能够正常截止,当时正是是root身份kill-9也不能杀死尸鬼过程。补救措施是杀死尸鬼进度的父进程(尸鬼进程的父进程必然存在卡塔尔,丧尸进度成为”孤儿进程”,过继给1号经过init,init会准时调用wait回笼清理那些父进程已脱离的丧尸子进度。

      所以,上边的演示能够改成:

       //…..
//须要安装pcntl的php扩张,并加载它
if(function_exists(“pcntl_fork”)){
//生成第贰个头进度
$pid = pcntl_fork(State of Qatar; //$pid即所发生的子进度id
if($pid == -1){
//子进程fork失败
die(‘could not fork’);
}else{
if($pid){
//父进程code
sleep(5); //等待5秒
exit(0); //或$this->_redirect(‘/’);
}else{
//第一身形进度code
//产生孙进度
if(($gpid = pcntl_fork(State of QatarState of Qatar < 0卡塔尔国{ ////$gpid即所发生的孙进度id
//孙进度产生挫败
die(‘could not fork’);
}elseif($gpid > 0){
//第一个子进度code,即孙进程的父进程
$status = 0;
$status = pcntl_wait($status卡塔尔(قطر‎;
//窒碍子进程,并再次回到孙进度的退出状态,用于检查是不是健康退出
if($status ! = 0) file_put_content(‘filename’, ‘孙进度特别退出’卡塔尔(قطر‎;
//得到父进度id
//$ppid = posix_getppid(卡塔尔;
//假设$ppid为1则意味着其父进度已改为init进度,原父进程已脱离
//得到子进度id:posix_getpid(State of Qatar或getmypid(卡塔尔国或是fork重返的变量$pid
//kill掉子进度
//posix_kill(getmypid(), SIGTERM);
exit(0);
}else{ //即$gpid == 0
//孙进程code
//….
//截止孙进程(即近些日子经过卡塔尔(قطر‎,以免止生成尸鬼进度
if(function_exists(‘posix_kill’)){
posix_kill(getmypid(), SIGTERM);
}else{
system(‘kill -9’. getmypid());
}
exit(0);
}
}
}
}else{
// 不协理多进度管理时的代码在这里处
}
//…..
?>

怎样发生尸鬼进度的
三个历程在调用exit命令截止本身的人命的时候,其实它并未当真的被销毁,而是留给二个叫作尸鬼进度(Zombie)的数据构造(系统调用exit,它的效应是使进程退出,但也只有限于将三个不奇怪化的经过形成二个活死人进程,并不能够将其完全灭亡)。在Linux进度的情形中,丧尸进度是拾壹分非常的一种,它已经吐弃了大约具有内部存款和储蓄器空间,未有别的可实行代码,也不可能被调节,仅仅在经过列表中保留三个岗位,记载该进度的脱离状态等新闻供别的进度收罗,除外,尸鬼进度不再据有任何内部存款和储蓄器空间。它必要它的父进程来为它收尸,就算他的父进度没安装SIGCHLD实信号管理函数调用wait或waitpid(卡塔尔(قطر‎等待子进度甘休,又从不显式忽视该时域信号,那么它就一贯维系活死人状态,假使这时候父进度截止了,那么init进度自动会接任那几个子进度,为它收尸,它还是能够被毁灭的。不过假使一旦父进程是二个循环,不会终结,那么子进度就能够直接维持活死人状态,那正是为什么系统中不时会有为数不菲的尸鬼进度。

别的叁个子进程(init除了这些之外卡塔尔国在exit(卡塔尔之后,实际不是立即就消失掉,而是留给三个誉为丧尸进度(Zombie卡塔尔(قطر‎的数据构造,等待父进度管理。那是各样子进度在完工作时间都要通过的阶段。如若实进程在exit(卡塔尔国之后,父进度没有来得及管理,当时用ps命令就能够看到子进度的境况是”Z”。如若父进程能及时
管理,或然用ps命令就来比不上看见子进程的丧尸状态,但那并不等于子进度不经过丧尸状态。

假定父进度在子进度甘休早先退出,则子进度将由init接管。init将会以父进度的地位对丧尸状态的子进程进行管理。

别的,还可以够写一个php文件,然后在现在台情势来运作它,比方:

//Action代码
public function createAction(){
//….
//将args替换到要传给insertLargeData.php的参数,参数间用空格间距
system(‘php -f insertLargeData.php ‘ . ‘ args ‘ . ‘&’);
$this->redirect(‘/’);
}
?>

然后在insertLargeData.php文件中做数据库操作。也得以用cronjob

  • php的不二等秘书诀完成大数据量的管理。

万一是在尖峰运营php命令,当终端关闭后,刚刚执行的指令也会被劫持关闭,借使你想让其不受终端关闭的影响,能够应用nohup命令落成:

//Action代码
public function createAction(){
//….
//将args替换到要传给insertLargeData.php的参数,参数间用空格间距
system(‘nohup php -f insertLargeData.php ‘ . ‘ args ‘ . ‘&’);
$this->redirect(‘/’);
}
?>

你还能使用screen命令取代nohup命令。

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图