PHP的進程控制支持實現(xiàn)了Unix方式的進程創(chuàng)建, 程序執(zhí)行, 信號處理以及進程的中斷叨襟。 進程控制不能被應(yīng)用在Web服務(wù)器環(huán)境揍魂,當其被用于Web服務(wù)環(huán)境時可能會帶來意外的結(jié)果。需要注意的是 PCNTL
是不支持在windows系統(tǒng)環(huán)境下使用的蚀浆。
- PCNTL 多進程阻塞形式
<?php
$childProcessNum = 5;
for($i = 0; $i < $childProcessNum; ++$i) {
$pids = pcntl_fork();
if($pids == -1) {
die('fork error');
} else if ($pids) {
pcntl_wait($status);
} else {
sleep(mt_rand(3,5));
echo "{$i}\n";
exit;
}
}
在cli模式下執(zhí)行智厌,在終端可以看到會按順序來輸出每個執(zhí)行的進程的序號
picture
- PCNTL 多進程非阻塞形式
要使用非阻塞的多進程則只需要設(shè)置pcntl_wait
的第二個參數(shù)為WNOHANG
即可陈哑,即:
<?php
$childProcessNum = 5;
for($i = 0; $i < $childProcessNum; ++$i) {
$pids = pcntl_fork();
if($pids == -1) {
die('fork error');
} else if ($pids) {
pcntl_wait($status, WNOHANG);
} else {
sleep(mt_rand(3,5));
echo "{$i} - ";
exit;
}
}
pcntl_wait
在官方手冊中是這樣說明的:wait函數(shù)刮起當前進程的執(zhí)行直到一個子進程退出或接收到一個信號要求中斷當前進程或調(diào)用一個信號處理函數(shù)妻坝。 如果一個子進程在調(diào)用此函數(shù)時已經(jīng)退出(俗稱僵尸進程)伸眶,此函數(shù)立刻返回。子進程使用的所有系統(tǒng)資源將被釋放刽宪。
int pcntl_wait ( int &$status [, int $options = 0 ] )
pcntl_wait
這個函數(shù)有兩個參數(shù)厘贼,第二個參數(shù)的說明如下:
image
在cli模式下執(zhí)行修改后的代碼,可以看到腳本已經(jīng)執(zhí)行完畢了纠屋,不過子進程由于sleep的原因還沒執(zhí)行完涂臣,過了幾面才在終端輸出執(zhí)行結(jié)果。
此時用ps可以看到后臺有5個進程正在執(zhí)行:
image
執(zhí)行結(jié)果:
image
- 配合
ticks
實現(xiàn)在同一時刻是控制進程數(shù)量
<?php
$maxProcess = 2;
$runningProcess = 0;
$arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
declare (ticks = 1);
pcntl_signal(SIGCHLD, function ($signo) {
global $runningProcess;
switch ($signo) {
case SIGCHLD:
$runningProcess--;
break;
}
});
for($i = 0; $i < 7; ++$i) {
$runningProcess++;
$pids = pcntl_fork();
if($pids == -1) {
die('fork error');
} else if ($pids) {
if ($runningProcess > $maxProcess) {
pcntl_wait($status);
}
} else {
sleep(mt_rand(3,4));
echo "{$arr[$i]} \n";
exit;
}
}
- 同一時刻控制子進程數(shù)量
<?php
$max = 3;
$child = 0;
$arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
function sig_handler($signo) {
switch ($signo) {
case SIGCHLD:
echo "SIGCHLD received\n";
$child--;
}
}
pcntl_signal(SIGCHLD, "sig_handler");
for ($i=0; $i < 7; $i++) {
$child++;
$pid=pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {
if ( $child >= $max ) pcntl_wait($status);
} else {
echo "\t Starting new child | now we de have $child child processes $arr[$i]\n";
sleep(rand(4,5));
exit;
}
}