成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊 PHP 多進(jìn)程模式下的孤兒進(jìn)程和僵尸進(jìn)程

開(kāi)發(fā) 前端
從生活化的例子來(lái)說(shuō)就是,你不能只管生娃,生完之后就不管養(yǎng)育了,這種操作肯定是不行的,道德和法律層面這一關(guān)你都過(guò)不去。利用 pcntl_wait 這個(gè)函數(shù)可以很優(yōu)雅的解決了孤兒進(jìn)程和僵尸進(jìn)程,但在實(shí)際的編程中很容易忽視這一點(diǎn),因此這一點(diǎn)值得注意。

大家好,我是碼農(nóng)先森。

在 PHP 的編程實(shí)踐中多進(jìn)程通常都是在 cli 腳本的模式下使用,我依稀還記得在多年以前為了實(shí)現(xiàn)從數(shù)據(jù)庫(kù)導(dǎo)出千萬(wàn)級(jí)別的數(shù)據(jù),第一次在 PHP 腳本中采用了多進(jìn)程編程。

在此之前我從未接觸過(guò)多進(jìn)程,只知道 PHP-FPM 進(jìn)程管理器是多進(jìn)程模型,但從未在編程中進(jìn)行實(shí)踐。多進(jìn)程雖然能帶來(lái)效率上的提升,但依然會(huì)帶來(lái)不少的問(wèn)題,如果初學(xué)者使用多進(jìn)程,那注定會(huì)遇到各種奇奇怪怪的 Bug 比如并發(fā)操作數(shù)據(jù)庫(kù)引起死鎖、共用內(nèi)存變量資源造成串?dāng)?shù)據(jù)、忘記回收進(jìn)程資源導(dǎo)致產(chǎn)生孤兒進(jìn)程、僵尸進(jìn)程等。

反正如果我們長(zhǎng)期都是 PHP-FPM 模式下編程的話,在使用多進(jìn)程編程時(shí)需要慎之又慎,避免出現(xiàn)意想不到的問(wèn)題。不過(guò)這次我想分享的內(nèi)容是多進(jìn)程模式下的孤兒進(jìn)程和僵尸進(jìn)程,通過(guò)示例代碼來(lái)看看這兩者進(jìn)程是如何產(chǎn)生的,又應(yīng)該如何解決,內(nèi)容不難但是在實(shí)際的編程中是可能比較容易忽視的點(diǎn)。

按照慣例我們先看看孤兒進(jìn)程和僵尸進(jìn)程的基礎(chǔ)概念。

  • 孤兒進(jìn)程:是指一個(gè)進(jìn)程的父進(jìn)程已經(jīng)終止,但該子進(jìn)程仍然在運(yùn)行。當(dāng)父進(jìn)程結(jié)束時(shí),操作系統(tǒng)會(huì)將其所有的子進(jìn)程重新分配給 init 進(jìn)程。init 進(jìn)程會(huì)負(fù)責(zé)這些孤兒進(jìn)程,并確保它們能夠正確結(jié)束。孤兒進(jìn)程不會(huì)造成資源泄漏,因?yàn)樽罱K它們會(huì)被 init 進(jìn)程管理并正確清理。
  • 僵尸進(jìn)程:是指一個(gè)已經(jīng)完成執(zhí)行的進(jìn)程,但仍在進(jìn)程表中保留了一些信息。這通常發(fā)生在父進(jìn)程未調(diào)用 wait() 或相關(guān)函數(shù)來(lái)獲取子進(jìn)程的退出狀態(tài)時(shí)。僵尸進(jìn)程處于 Z 狀態(tài),是一種占用系統(tǒng)資源但不占用 CPU 的進(jìn)程。僵尸進(jìn)程會(huì)繼續(xù)占用系統(tǒng)的進(jìn)程 ID,如果大量產(chǎn)生將導(dǎo)致進(jìn)程 ID 耗盡,可能會(huì)影響系統(tǒng)的正常運(yùn)行。

這兩者進(jìn)程的基礎(chǔ)概念應(yīng)該還比較好理解,孤兒進(jìn)程的產(chǎn)生就是緣于父進(jìn)程的不負(fù)責(zé),自己先跑路了,導(dǎo)致自己的子進(jìn)程變成了孤兒,最后孤兒進(jìn)程被系統(tǒng)給回收了,可以理解為被政府的福利院收養(yǎng)了。

僵尸進(jìn)程的產(chǎn)生就是兒子進(jìn)程執(zhí)行完了沒(méi)有退出,但是父進(jìn)程又不知情,無(wú)法及時(shí)回收兒子進(jìn)程的資源,導(dǎo)致自己的兒子進(jìn)程變成了僵尸進(jìn)程,僵尸進(jìn)程往往比孤兒進(jìn)程對(duì)系統(tǒng)的危害更大,接下來(lái)我們來(lái)看看具體的代碼示例。

首先看看孤兒進(jìn)程示例,使用 pcntl_fork 函數(shù)創(chuàng)建了一個(gè)子進(jìn)程,子進(jìn)程會(huì)每間隔 1 秒鐘獲取一次自己進(jìn)程的 ID 和父進(jìn)程的 ID,而父進(jìn)程在 2 秒鐘之后就退出跑路了,自此子進(jìn)程就變成了孤兒進(jìn)程,被系統(tǒng)進(jìn)程收養(yǎng)了。

<?php

// 孤兒進(jìn)程示例

$pid = pcntl_fork();
if ($pid < 0) {
   exit('fork error');
} else if($pid > 0) {
   // 父進(jìn)程執(zhí)行空間 ...
   // getmypid 函數(shù)獲取當(dāng)前父進(jìn)程ID
   echo "父進(jìn)程ID: " . getmypid() . PHP_EOL;

   // 2 秒之后退出當(dāng)前的父進(jìn)程
   // 父進(jìn)程先行跑路了
   sleep(2);
   exit();
}

// 子進(jìn)程執(zhí)行空間 ...
// getmypid 函數(shù)獲取當(dāng)前子進(jìn)程ID
$cid = getmypid();
echo "當(dāng)前子進(jìn)程: {$cid}" . PHP_EOL;

// 每隔 1 秒獲取一下進(jìn)程ID
for($i = 1; $i <= 10; $i++){
    // posix_getppid 函數(shù)獲取當(dāng)前子進(jìn)程的父進(jìn)程ID
    sleep(1);
    echo "當(dāng)前子進(jìn)程ID: " . $cid. ", 父進(jìn)程ID: " . posix_getppid() . PHP_EOL;
}

// 由于父進(jìn)程跑路了,子進(jìn)程變成了孤兒進(jìn)程 ...

執(zhí)行 php index.php 觀察輸出結(jié)果,可以看出間隔一段時(shí)間之后父進(jìn)程的 ID 就變成 1 了,即為系統(tǒng)進(jìn)程。

## 執(zhí)行程序
[manongsen@root php_test]$ php index.php 
父進(jìn)程ID: 3484
當(dāng)前子進(jìn)程: 3485
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 3484
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 3484
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1
當(dāng)前子進(jìn)程ID: 3485, 父進(jìn)程ID: 1

然后再看看僵尸進(jìn)程示例,同樣也使用 pcntl_fork 創(chuàng)建了一個(gè)子進(jìn)程,然后子進(jìn)程先行執(zhí)行完了,父進(jìn)程還未執(zhí)行完,這時(shí)子進(jìn)程變成為了僵尸進(jìn)程。當(dāng)然僵尸進(jìn)程也不會(huì)一直存在,如果父進(jìn)程退出了其也會(huì)結(jié)束自身進(jìn)程,反之就會(huì)一直存在占用著系統(tǒng)資源。

<?php

// 僵尸進(jìn)程示例

$pid = pcntl_fork();
if ($pid < 0) {
   exit('fork error');
} else if($pid > 0) {
   // 父進(jìn)程執(zhí)行空間 ...
   // getmypid 函數(shù)獲取當(dāng)前父進(jìn)程ID
   echo "父進(jìn)程ID: " . getmypid() . PHP_EOL;

   // 120 秒之后退出當(dāng)前的父進(jìn)程
   sleep(120);
   exit();
}

// 子進(jìn)程執(zhí)行空間 ...
// getmypid 函數(shù)獲取當(dāng)前子進(jìn)程ID
$cid = getmypid();
echo "當(dāng)前子進(jìn)程: {$cid}" . PHP_EOL;

// 10 秒之后退出子進(jìn)程
sleep(10);

執(zhí)行 php index.php 觀察輸出結(jié)果,通過(guò)查看子進(jìn)程信息中有一個(gè) Z+ 標(biāo)識(shí),則表示該進(jìn)程已經(jīng)成為了僵尸進(jìn)程。

## 執(zhí)行程序
[manongsen@root php_test]$ php index.php 
父進(jìn)程ID: 85804
當(dāng)前子進(jìn)程: 85805

## 查看進(jìn)程信息
[manongsen@root php_test]$ ps aux | grep 85805
root             90776   0.0  0.0 408169072   1408 s060  U+    22:06下午   0:00.00 grep 85805
root             85805   0.0  0.0         0      0 s062  Z+    22:06下午   0:00.00 (php)

最后來(lái)看看正常進(jìn)程的示例,也先使用 pcntl_fork 創(chuàng)建了一個(gè)子進(jìn)程,但與上面兩個(gè)例子不同的是在其父進(jìn)程中會(huì)調(diào)用 pcntl_wait 函數(shù)一直等待子進(jìn)程結(jié)束。在子進(jìn)程 10 秒鐘過(guò)后,父進(jìn)程會(huì)接受到子進(jìn)程執(zhí)行完畢的通知,然后回收子進(jìn)程的資源。

<?php

// 正常進(jìn)程示例

$pid = pcntl_fork();
if ($pid < 0) {
   exit('fork error');
} else if($pid > 0) {
    // 父進(jìn)程執(zhí)行空間 ...
    // getmypid 函數(shù)獲取當(dāng)前父進(jìn)程ID
    echo "父進(jìn)程ID: " . getmypid() . PHP_EOL;

    // 一直等待到子進(jìn)程結(jié)束后回收資源
    $cid = pcntl_wait($status);
    echo "父進(jìn)程ID: " . getmypid() . ", 接收到子進(jìn)程ID: {$cid} 退出" . PHP_EOL;
    exit();
}

// 子進(jìn)程執(zhí)行空間 ...
// getmypid 函數(shù)獲取當(dāng)前子進(jìn)程ID
$cid = getmypid();
echo "當(dāng)前子進(jìn)程: {$cid}" . PHP_EOL;

// 睡眠 10 秒
sleep(10);

執(zhí)行 php index.php 觀察輸出結(jié)果,可以看出子進(jìn)程執(zhí)行完畢之后,父進(jìn)程接收到了子進(jìn)程的通知。

## 執(zhí)行程序
[manongsen@root php_test]$ php index.php 
父進(jìn)程ID: 49954
當(dāng)前子進(jìn)程: 49955
父進(jìn)程ID: 49954, 接收到子進(jìn)程ID: 49955 退出

## 查看進(jìn)程 49955
[manongsen@root php_test]$ ps aux | grep 49955
root             19516   0.0  0.0 407972944   1216 s062  R+    22:23下午   0:00.00 grep 49955
root             49955   0.0  0.0 437931336    372 s060  S+    22:23下午   0:00.00 php index.php

## 再次查看進(jìn)程 49955
[manongsen@root php_test]$ ps aux | grep 49955
root             26599   0.0  0.0 407963440    480 s062  R+    22:24下午   0:00.00 grep 49955

通過(guò)這上面的例子可以看出,多進(jìn)程中正確的使用方式是要在父進(jìn)程中使用 pcntl_wait 函數(shù)等待子進(jìn)程的結(jié)束,而不是只管 pcntl_fork 生產(chǎn)完子進(jìn)程,然后就對(duì)子進(jìn)程不聞不問(wèn)了。

從生活化的例子來(lái)說(shuō)就是,你不能只管生娃,生完之后就不管養(yǎng)育了,這種操作肯定是不行的,道德和法律層面這一關(guān)你都過(guò)不去。利用 pcntl_wait 這個(gè)函數(shù)可以很優(yōu)雅的解決了孤兒進(jìn)程和僵尸進(jìn)程,但在實(shí)際的編程中很容易忽視這一點(diǎn),因此這一點(diǎn)值得注意。

責(zé)任編輯:武曉燕 來(lái)源: 碼農(nóng)先森
相關(guān)推薦

2025-05-29 08:10:00

Linux進(jìn)程系統(tǒng)

2021-09-14 13:25:23

容器pod僵尸進(jìn)程

2017-12-15 09:40:47

Linux僵尸進(jìn)程

2009-04-21 09:12:45

Java多進(jìn)程運(yùn)行

2017-06-30 10:12:46

Python多進(jìn)程

2021-11-06 10:17:38

Linux僵尸進(jìn)程

2021-11-08 10:30:30

Linux僵尸命令

2019-02-26 11:15:25

進(jìn)程多線程多進(jìn)程

2020-11-18 09:06:04

Python

2010-02-25 10:28:43

Linux進(jìn)程管理

2010-07-15 12:51:17

Perl多進(jìn)程

2010-10-15 08:57:15

PHP多進(jìn)程

2024-02-05 18:23:23

父進(jìn)程應(yīng)用程序程序

2012-08-08 09:32:26

C++多進(jìn)程并發(fā)框架

2016-01-11 10:29:36

Docker容器容器技術(shù)

2021-10-12 09:52:30

Webpack 前端多進(jìn)程打包

2024-03-29 06:44:55

Python多進(jìn)程模塊工具

2021-04-20 12:39:52

Node.js多線程多進(jìn)程

2022-02-07 11:55:00

linux進(jìn)程線程

2010-07-26 09:45:09

Perl多進(jìn)程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲精品久久久久avwww潮水 | 日韩精品免费一区二区在线观看 | 99精品免费 | 人人九九精 | www日韩高清 | 九九久久这里只有精品 | 日韩欧美在 | 欧美国产日本一区 | 久久亚洲国产精品日日av夜夜 | 国内自拍偷拍视频 | 看羞羞视频 | 99久久精品国产一区二区三区 | 精品视频一区二区三区四区 | 中文字幕久久精品 | 国产一区二区在线视频 | 成人三级av | 91国产视频在线 | 亚洲精品国产区 | 99热在线播放 | 91精品国产高清一区二区三区 | 欧美在线视频一区二区 | 国产欧美在线视频 | 日韩五月天| 欧美在线视频一区 | 久久久久久久久久一区二区 | 亚洲视频在线看 | 在线免费观看视频黄 | 久在线视频播放免费视频 | 成人妇女免费播放久久久 | 亚州精品成人 | 国产精品久久在线观看 | 亚洲一区二区成人 | 欧美大片一区 | 国产成人免费视频网站视频社区 | av一二三区 | 成人伊人 | 综合网视频 | 国产91丝袜在线播放 | 91九色porny首页最多播放 | 亚洲免费网 | 日韩一级免费大片 |