深入探究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(卡塔尔国;时,在这里个地点开展分层,父亲和儿子进度各自先导运维各自的程序代码。代码的运作结果是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
2012-01-14 15:04:21二零一一-01-14
15:04:21因为三个进度同期实行写操作,产生了冲突。

2. 不通方式

用直接格局,父进度创设了子进度后,并不曾等待子进程结束,而是继续运营。就像这里看不到有如何难点。假诺php脚本并非运作完后机动终止,而是常驻内部存款和储蓄器的,就能产生子进度不能够回笼的难题。也正是活死人进程。可以因此pcntl_wai(卡塔尔方法等待历程截止,然后回笼已经完工的历程。将测量试验脚本改成:

$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(卡塔尔国将本人过不去,等待子进程运转完了才跟着运营。

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(State of Qatar这么些工具,利用内部的四线程,访谈多少个链接,各样链接能够看做多少个职务。

编纂脚本 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再次回到子进程的状态码,并能够钦点第叁个参数来证实是还是不是以堵塞状态调用:
      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
(Final卡塔尔),优先级为-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(卡塔尔(قطر‎函数进行财富自由。但在
pcntl_waitpid(卡塔尔不显著释放的正是时下运作的经过,也或许是过去变动的活死人进度(未有自由卡塔尔国;也说倒霉是并发时别的报事人的丧尸进度。但能够运用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退出State of Qatar都会成为尸鬼进程(用于保存进度的情状等新闻State of Qatar,然后由init进度接管。假使不立时回笼尸鬼进度,那么它在系统中就能够据有三个历程表项,假使这种活死人进迈过多,最后系统就一向不得以用的历程表项,于是也无从再运转此外的次序。

谨防丧尸进度有以下三种艺术:

   1.
父进度经过wait和waitpid等函数使其等待子进度甘休,然后再进行父进度中的代码,这会导致父进程挂起。下边包车型客车代码便是运用这种办法达成的,但在WEB境况下,它不符合子进度供给长日子运作的状态(会导致超时卡塔尔国。

     
使用wait和waitpid方法使父进度自动回笼其活死人子进度(依照子进程的回到状态卡塔尔(قطر‎,waitpid用于临控钦命子进度,wait是对此所有子进度来讲。
   2.
若是父进度很忙,那么能够用signal函数为SIGCHLD安装handler,因为子进程甘休后,父进程会收到该复信号,能够在handler中调用wait回笼
   3. 借使父进度不关注子进程几时甘休,那么可以用signal(SIGCHLD,
SIG_IGN卡塔尔国通告内核,本身对子进度的结束不感兴趣,那么子进度截止后,内核会回笼,并不再给父进度发送复信号,例如:

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(State of Qatar/execve(卡塔尔进度中,要是子进程甘休时父进度仍存在,而父进度fork(卡塔尔以前既没设置SIGCHLD能量信号管理函数调用
waitpid(卡塔尔国等待子进度结束,又从不显式忽视该能量信号,则子进度成为丧尸进度,不得不荒谬甘休,那个时候即便是root身份kill-9也不能够杀死活死人进度。补救措施是杀死尸鬼进度的父进度(丧尸进度的父进程必然存在卡塔尔,丧尸过程成为”孤儿进度”,过继给1号经过init,init会准时调用wait回笼清理这个父进度已退出的丧尸子进度。

      所以,上面包车型地铁演示能够改成:

       //…..
//必要安装pcntl的php扩大,并加载它
if(function_exists(“pcntl_fork”)){
//生成第一体态进度
$pid = pcntl_fork(卡塔尔(قطر‎; //$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(卡塔尔卡塔尔国 < 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(卡塔尔或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除此之外State of Qatar在exit(State of Qatar之后,并非立刻就消失掉,而是留给一个称呼丧尸进度(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地图