PHP的pcntl進程控制教程三(多進程消費模型)

多進程消費模型

父進程等待並控制子進程的退出

思路整理

父進程開啓後,直接獲取到子進程的pid,而後存入child數組,子進程fork出來後直接開啓業務消費代碼,而後exit(0)退出,而後父進程pcntl_wait等待子進程退出,所有退出後父進程結束

代碼

const NEWLINE = "\n\n";

if (strtolower(php_sapi_name()) != 'cli') {
    die("請在cli模式下運行");
}

$bizPath = "./childBiz/";

if (!is_dir($bizPath)) {
    @mkdir($bizPath, 0755, true);
}

$child = [];

$index = 0;
$loop = 10; //子進程的數量

//若是是資源類型的變量,父子進程會共享
//$f = fopen("./pcntl_fork_2.php", "r");

while ($index < $loop) {

    echo "當前進程:" . getmypid() . NEWLINE;

    $pid = pcntl_fork(); //fork出子進程

    //fork後父進程會走本身的邏輯,子進程從處開始走本身的邏輯,堆棧信息會徹底複製給子進程內存空間,父子進程相互獨立

    if ($pid == -1) { // 建立錯誤,返回-1

        die('進程fork失敗');

    } else if ($pid) { // $pid > 0, 若是fork成功,返回子進程id

        //獲取建立的子進程
        $child[$pid] = $pid;
        echo "{$pid} child create!" . microtime(true) . NEWLINE;

    } else { // $pid = 0

        // 子進程邏輯
        $sleepTime = rand(5, 18);
        sleep($sleepTime);
        $time = microtime(true);
        file_put_contents($bizPath.getmypid().".log", $time . ":" . $index . PHP_EOL, FILE_APPEND);
        exit(0);
    }
    $index++;
}

while (count($child)) {
    //阻塞等待
    $pid = pcntl_wait($status);
    $time = microtime(true);
    file_put_contents("./father.log", $time . ":" . $pid . ":" . $status . PHP_EOL, FILE_APPEND);
    if ($pid > 0) {
        unset($child[$pid]);
    }
    if ($pid == -1) {
        unset($child);
    }
//    foreach ($child as $k => $pid) {
//        //不阻塞循環判斷 WNOHANG表示若是沒有子進程退出馬上返回
//        $res = pcntl_waitpid($pid, $status, WNOHANG);
//        $time = microtime(true);
//        file_put_contents("./father.log", $time . ":" . $pid . ":" . $res . ":" . $status . PHP_EOL, FILE_APPEND);
//        if (-1 == $res || $res > 0) {
//            unset($child[$k]);
//        }
//    }
}

//fclose($f);
//主進程退出
exit(0);
相關文章
相關標籤/搜索