当前位置:首页 > 后端开发 > 正文内容

聊聊 PHP 多进程形式下的孤儿进程和僵尸进程

邻居的猫1个月前 (12-09)后端开发516

大家好,我是码农先森。

在 PHP 的编程实践中多进程一般都是在 cli 脚本的形式下运用,我模糊还记得在多年曾经为了实现从数据库导出千万等级的数据,第一次在 PHP 脚本中采用了多进程编程。在此之前我从未触摸过多进程,只知道 PHP-FPM 进程办理器是多进程模型,但从未在编程中进行实践。多进程虽然能带来功率上的提高,但仍然会带来不少的问题,假如初学者运用多进程,那注定会遇到各种奇奇怪怪的 Bug 比方并发操作数据库引起死锁、共用内存变量资源形成串数据、忘掉收回进程资源导致发生孤儿进程、僵尸进程等。横竖假如咱们长时间都是 PHP-FPM 形式下编程的话,在运用多进程编程时需求慎之又慎,防止呈现意想不到的问题。不过这次我想共享的内容是多进程形式下的孤儿进程和僵尸进程,经过示例代码来看看这两者进程是怎么发生的,又应该怎么处理,内容不难可是在实践的编程中是或许比较简单忽视的点。

依照常规咱们先看看孤儿进程和僵尸进程的根底概念。

  • 孤儿进程:是指一个进程的父进程现已停止,但该子进程仍然在运转。当父进程完毕时,操作体系会将其所有的子进程从头分配给 init 进程。init 进程会担任这些孤儿进程,并保证它们能够正确完毕。孤儿进程不会形成资源走漏,因为终究它们会被 init 进程办理并正确整理。
  • 僵尸进程:是指一个现已完结履行的进程,但仍在进程表中保留了一些信息。这一般发生在父进程未调用 wait() 或相关函数来获取子进程的退出状况时。僵尸进程处于 Z 状况,是一种占用体系资源但不占用 CPU 的进程。僵尸进程会持续占用体系的进程 ID,假如很多发生将导致进程 ID 耗尽,或许会影响体系的正常运转。

这两者进程的根底概念应该还比较好了解,孤儿进程的发生便是缘于父进程的不担任,自己先跑路了,导致自己的子进程变成了孤儿,最终孤儿进程被体系给收回了,能够了解为被政府的福利院收养了。僵尸进程的发生便是儿子进程履行完了没有退出,可是父进程又不知情,无法及时收回儿子进程的资源,导致自己的儿子进程变成了僵尸进程,僵尸进程往往比孤儿进程对体系的损害更大,接下来咱们来看看详细的代码示例。

首要看看孤儿进程示例,运用 pcntl_fork 函数创建了一个子进程,子进程会每距离 1 秒钟获取一次自己进程的 ID 和父进程的 ID,而父进程在 2 秒钟之后就退出跑路了,自此子进程就变成了孤儿进程,被体系进程收养了。

<?php

// 孤儿进程示例

$pid = pcntl_fork();
if ($pid < 0) {
   exit('fork error');
} else if($pid > 0) {
   // 父进程履行空间 ...
   // getmypid 函数获取当时父进程ID
   echo "父进程ID: " . getmypid() . PHP_EOL;

   // 2 秒之后退出当时的父进程
   // 父进程先行跑路了
   sleep(2);
   exit();
}

// 子进程履行空间 ...
// getmypid 函数获取当时子进程ID
$cid = getmypid();
echo "当时子进程: {$cid}" . PHP_EOL;

// 每隔 1 秒获取一下进程ID
for($i = 1; $i <= 10; $i++){
    // posix_getppid 函数获取当时子进程的父进程ID
    sleep(1);
    echo "当时子进程ID: " . $cid. ", 父进程ID: " . posix_getppid() . PHP_EOL;
}

// 因为父进程跑路了,子进程变成了孤儿进程 ...

履行 php index.php 调查输出成果,能够看出距离一段时间之后父进程的 ID 就变成 1 了,即为体系进程。

## 履行程序
[manongsen@root php_test]$ php index.php 
父进程ID: 3484
当时子进程: 3485
当时子进程ID: 3485, 父进程ID: 3484
当时子进程ID: 3485, 父进程ID: 3484
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1
当时子进程ID: 3485, 父进程ID: 1

然后再看看僵尸进程示例,相同也运用 pcntl_fork 创建了一个子进程,然后子进程先行履行完了,父进程还未履行完,这时子进程变成为了僵尸进程。当然僵尸进程也不会一向存在,假如父进程退出了其也会完毕本身进程,反之就会一向存在占用着体系资源。

<?php

// 僵尸进程示例

$pid = pcntl_fork();
if ($pid < 0) {
   exit('fork error');
} else if($pid > 0) {
   // 父进程履行空间 ...
   // getmypid 函数获取当时父进程ID
   echo "父进程ID: " . getmypid() . PHP_EOL;

   // 120 秒之后退出当时的父进程
   sleep(120);
   exit();
}

// 子进程履行空间 ...
// getmypid 函数获取当时子进程ID
$cid = getmypid();
echo "当时子进程: {$cid}" . PHP_EOL;

// 10 秒之后退出子进程
sleep(10);

履行 php index.php 调查输出成果,经过检查子进程信息中有一个 Z+ 标识,则表明该进程现已成为了僵尸进程。

## 履行程序
[manongsen@root php_test]$ php index.php 
父进程ID: 85804
当时子进程: 85805

## 检查进程信息
[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)

最终来看看正常进程的示例,也先运用 pcntl_fork 创建了一个子进程,但与上面两个比如不同的是在其父进程中会调用 pcntl_wait 函数一向等候子进程完毕。在子进程 10 秒钟往后,父进程会接受到子进程履行完毕的告诉,然后收回子进程的资源。

<?php

// 正常进程示例

$pid = pcntl_fork();
if ($pid < 0) {
   exit('fork error');
} else if($pid > 0) {
    // 父进程履行空间 ...
    // getmypid 函数获取当时父进程ID
    echo "父进程ID: " . getmypid() . PHP_EOL;

    // 一向等候到子进程完毕后收回资源
    $cid = pcntl_wait($status);
    echo "父进程ID: " . getmypid() . ", 接纳到子进程ID: {$cid} 退出" . PHP_EOL;
    exit();
}

// 子进程履行空间 ...
// getmypid 函数获取当时子进程ID
$cid = getmypid();
echo "当时子进程: {$cid}" . PHP_EOL;

// 睡觉 10 秒
sleep(10);

履行 php index.php 调查输出成果,能够看出子进程履行完毕之后,父进程接纳到了子进程的告诉。

## 履行程序
[manongsen@root php_test]$ php index.php 
父进程ID: 49954
当时子进程: 49955
父进程ID: 49954, 接纳到子进程ID: 49955 退出

## 检查进程 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

## 再次检查进程 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

经过这上面的比如能够看出,多进程中正确的运用方法是要在父进程中运用 pcntl_wait 函数等候子进程的完毕,而不是只管 pcntl_fork 出产完子进程,然后就对子进程漠不关心了。从生活化的比如来说便是,你不能只管生娃,生完之后就不论哺育了,这种操作肯定是不可的,品德和法令层面这一关你都过不去。使用 pcntl_wait 这个函数能够很高雅的处理了孤儿进程和僵尸进程,但在实践的编程中很简单忽视这一点,因而这一点值得注意。本次共享的内容就到这儿了,期望对大家能有所协助。

感谢阅览,个人观念仅供参考,欢迎在谈论区宣布不同观念。


欢迎重视、共享、点赞、保藏、在看,我是微信大众号「码农先森」作者。

扫描二维码推送至手机访问。

版权声明:本文由51Blog发布,如需转载请注明出处。

本文链接:https://www.51blog.vip/?id=191

分享给朋友:

“聊聊 PHP 多进程形式下的孤儿进程和僵尸进程” 的相关文章

RabbitMQ装置

RabbitMQ装置

首要装置Erlang环境 由于 RabbitMQ 需求 erlang 环境的⽀持,所以必须先装置 erlang 。 假如仅仅运用RabbitMQ,个人引荐运用RabbitMQ公司保护的erlang版别,该版别只保留了与RabbltMQ相关的功用, centOS6与7版别的都有,还有erlang19x...

r语言attach,深入理解R语言中的attach与detach函数

r语言attach,深入理解R语言中的attach与detach函数

在R语言中,`attach`函数用于将数据框(data frame)或列表(list)中的变量自动绑定到全局环境中,使得这些变量可以直接使用它们的名称而不需要前缀。这可以简化代码,使得对数据框或列表中的变量进行操作时更加方便。例如,假设你有一个名为`data`的数据框,其中包含变量`x`、`y`和`...

c语言开发工具

1. 集成开发环境(IDE): Visual Studio:微软开发的IDE,支持多种编程语言,包括C语言。它提供了代码编辑、编译、调试、版本控制等功能。 Code::Blocks:一个开源、跨平台的IDE,支持C/C 编程。它轻量级、易于使用,适合初学者。 Eclipse CD...

swift国际网站,您的金融通讯枢纽

Swift国际网站主要是用于银行间跨境支付和信息传输。以下是有关Swift国际网站的一些详细信息:1. 官方网站: Swift的官方网站是 。这个网站提供了关于Swift网络的数据和服务信息。2. 功能与用途: Swift网络主要用于跨境支付和金融机构间的信息传输。数据显示,90%的跨境...

rust服务器

1. Rust Web 全栈开发 课程简介:这门课程涵盖了使用 Rust 编写 Web 服务器的各个方面,包括 TCP 和 HTTP 服务器的构建。它使用 Rust 标准库中的 `std::net` 模块来创建 TCP 服务器和客户端。 2. 多线程 Web 服务器 实现方法:通过为每个请求分配...

php游戏源码,开发、应用与优化

php游戏源码,开发、应用与优化

1. 寻仙纪: 寻仙纪是一款在线多人文字游戏,需要PHP 5.6版本和MySQL 5.5版本的环境。MySQL高于5.5版本可能会导致无法建立角色的问题。支持Nginx、APACHE、IIS等WEB发布服务,但不支持Mariadb。你可以访问获取更多信息和下载源码。2. Ogame: O...