使用PHP真正的多进
PHP有一组进程控制
常用的PCNTL函数
- pcntl_alar
m ( int $seconds )设置一个$seco nds秒后发送SIG ALRM信号的计数器
- pcntl_sign
al ( int $signo , callback $handler [, bool $restart_s yscalls ] )为$signo设置 一个处理该信号的回调 函数。下面是一个隔5 秒发送一个SIGAL RM信号,并由sig nal_handle r函数获取,然后打印 一个“Caught SIGALRM”的例 子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<?php
declare(ticks = 1);
function signal_handler($signal) {
print "Caught SIGALRM\n";
pcntl_alarm(5);
}
pcntl_signal(SIGALRM, "signal_ha ndler", true);
pcntl_alarm(5);
for(;;) {
}
?>
- pcntl_exec
( string $path [, array $args [, array $envs ]] )在当前的进程空间中 执行指定程序,类似于 c中的exec族函数 。所谓当前空间,即载 入指定程序的代码覆盖 掉当前进程的空间,执 行完该程序进程即结束 。
1
2
3
4
5
6
7
8
9
10
11<?php
$dir = '/home/shankka/';
$cmd = 'ls';
$option = '-l';
$pathtobin= '/bin/ls';
$arg = array($cmd, $option, $dir);
pcntl_exec($pathtobin , $arg);
echo '123'; //不会执行到该行
?>
- pcntl_fork
( void )为当前进程创建一个 子进程,并且先运行父 进程,返回的是子进程 的PID,肯定大于零 。在父进程的代码中可 以用pcntl_wa it(&$statu s)暂停父进程知道他 的子进程有返回值。注 意:父进程的阻塞同时 会阻塞子进程。但是父 进程的结束不影响子进 程的运行。
父进程运行完了会接着运行子进程,这时子进 程会从执行pcntl _fork()的那条 语句开始执行(包括此 函数),但是此时它返 回的是零(代表这是一 个子进程)。在子进程 的代码块中最好有ex it语句,即执行完子 进程后立即就结束。否 则它会又重头开始执行 这个脚本的某些部分。
注意两点:
1. 子进程最好有一个exit;语句,防止不必 要的出错;
2. pcntl_fork间最好不要有其它语句 ,例如:
1
2
3
4
5
6
7
8
9
10$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
}
- pcntl_wait
( int &$status [, int $options ] )阻塞当前进程,只到 当前进程的一个子进程 退出或者收到一个结束 当前进程的信号。使用 $status返回子 进程的状态码,并可以 指定第二个参数来说明 是否以阻塞状态调用:
1. 阻塞方式调用的,函数返回值为子进程的pi d,如果没有子进程返 回值为-1;
2. 非阻塞方式调用,函数还可以在有子进程在运 行但没有结束的子进程 时返回0。
- pcntl_wait
pid ( int $pid , int &$status [, int $options ] )功能同pcntl_ wait,区别为wa itpid为等待指定 pid的子进程。当p id为-1时pcnt l_waitpid与 pcntl_wait 一样。在pcntl_ wait和pcntl _waitpid两个 函数中的$statu s中存了子进程的状态 信息,这个参数可以用 于pcntl_wif exited、pcn tl_wifstop ped、pcntl_ wifsignale d、pcntl_we xitstatus、 pcntl_wter msig、pcntl _wstopsig、 pcntl_wait pid这些函数。
例如:
1
2
3
4
5
6
7
8
9
10
11
12<?php
$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秒 才结束,而父进程阻塞 着直到子进程退出之后 才继续运行。
- pcntl_getp
riority ([ int $pid [, int $process_i dentifier ]] )取得进程的优先级, 即nice值,默认为 0,在我的测试环境的 linux中(Cen tOS release 5.2 (Final)),优 先级为-20到19, -20为优先级最高, 19为最低。(手册中 为-20到20)。
- pcntl_setp
riority ( int $priority [, int $pid [, int $process_i dentifier ]] )设置进程的优先级。
- posix_kill
可以给进程发送信号
- pcntl_sing
al用来设置信号的回 调函数
当父进程退出时,子进
当父进程退出时,子进
- 当父进程退出时,会有
一个INIT进程来领 养这个子进程。这个I NIT进程的进程号为 1,所以子进程可以通 过使用getppid ()来取得当前父进程 的pid。如果返回的 是1,表明父进程已经 变为INIT进程,则 原进程已经推出。 - 使用kill函数,向
原有的父进程发送空信 号(kill(pid , 0))。使用这个方法 对某个进程的存在性进 行检查,而不会真的发 送信号。所以,如果这 个函数返回-1表示父 进程已经退出。
除了上面的这两个方法
PHP多进程采集数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | <?php /** * Project: Signfork: php多线程库 * File: Signfork.c */ class Signfork{ /** * 设置子进程通信文件所 * @var string */ private $tmp_path='/tmp/'; /** * Signfork引擎 * 1、判断$arg类型 * @param object $obj 执行对象 * @param string|arr * 如:$arg,自动分 * @return array 返回 array(子进程序 */ public function run($obj,$arg=1){ if(!method_exi 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|arr * @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_wait $tmpfile=$this->tmp_path.'sfpid_'.$cid; $data[$spawns['total']?$spawns[$ids]:$ids]=file_get_c unlink($tmpfile); } return $data; } /** * Signfork子进 * 1、pcntl_fo * 2、file_put * 3、posix_ki * @param object $obj 待执行的对象 * @param object $i 子进程的序列ID,以 * @param object $param 用于输入对象$obj */ private function spawn($obj,$i,$param=null){ if(pcntl_fork $cid=getmypid(); file_put_c posix_kill exit; } } } ?> |