参考 基于PCNTL的PHP并发编程

PCNTL 是 PHP 中的一组进程控制函数,可以用来 fork(创建)进程,传输控制信号等。

在PHP中,进程控制支持默认关闭。编译时通过 --enable-pcntl 配置选项可以使 PHP的 CGI 或 CLI 版本打开进程控制支持(但是注意不要在 web 服务器中用 PCNTL,会导致不可预料的问题)。仅 Unix 类系统支持 PCNTL 模块。

PCNTL 原理

简单示例

<?php

//在当前进程当前位置产生分支(子进程)
$pid = pcntl_fork(); //父进程和子进程都会执行下面代码
if ($pid == -1) {
//错误处理:创建子进程失败时返回-1.
die('could not fork');
} else if ($pid) {
//父进程会得到子进程号,所以这里是父进程执行的逻辑
pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}

原理

PCNTL 中的一系列函数,都对应操作系统中的函数,例如 pcntl_fork 就对应 Linux 系统中的 fork 函数。

每次在进程中调用 fork 函数时,操作系统会把进程完整的复制一份,作为这个进程的子进程。此时,两个进程的唯一区别就是 PID(进程ID)和 PPID(父进程ID)。根据 fork 返回值的不同可以判断当前是在父进程还是子进程中,从而可以有不同的处理逻辑。

为了保证系统资源利用率,必须防止出现僵尸进程(进程结束后未回收资源)或孤儿进程(父进程提前结束),可以通过 pcntl_wait 或 pcntl_waitpid 函数来监控子进程。

常用函数

pcntl_fork

在当前进程的当前位置产生分支(子进程),父进程和子进程都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号,而子进程得到的是0。子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同。

语法:

int pcntl_fork ( void )

返回值:

  • 成功时,产生进程分支:

    • 在父进程执行线程内返回产生的子进程的PID
    • 在子进程执行线程内返回0
  • 失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。

pcntl_waitpid

挂起当前进程的执行,直到参数pid指定的进程号对应的进程退出, 或接收到一个信号要求中断当前进程或调用一个信号处理函数。

如果pid指定的子进程在此函数调用时已经退出(僵尸进程),此函数将立刻返回。

语法:

int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )

返回值:

  • 正常执行时返回退出的子进程进程号
  • 发生错误时返回-1,如果提供了 WNOHANG作为option(wait3可用的系统)并且没有可用子进程时返回0。

pcntl_wait

挂起当前进程,直到当前进程的一个子进程退出或接收到一个信号要求中断当前进程或调用一个信号处理函数。如果当前进程的一个子进程在调用此函数时已经退出(俗称僵尸进程),此函数立刻返回。子进程使用的所有系统资源将被释放。

pcntl_wait 等同于以-1作为参数pid 的值并且没有options参数来调用pcntl_waitpid() 函数。

示例

多子进程实现并发

多子进程时,需要注意避免僵尸进程,浪费资源:

<?php

$procNum = 3;
for($i = 0; $i < $procNum; $i++){
$nPID = pcntl_fork();//创建子进程
if ($nPID == 0){
work();
exit(0);
} elseif ($nPID == -1) {
die('could not fork');
} else {
// 如果在这里写 pcntl_wait($status),则只有当前进程执行完毕后才会创建下一个进程
}
}
// 父进程会执行下面的代码,等待子进程执行完毕,避免僵尸进程
$n = 0;
while ($n < $procNum) {
$nStatus = -1;
$nPID = pcntl_wait($nStatus);
if ($nPID > 0) {
++$n;
}
} function work(){
while(true){
$nPID = pcntl_fork();//创建子进程
if ($nPID == 0){
echo time();
exit(0);
}
pcntl_waitpid($nPID,$nStatus);
}
}

进程状态:

[root@VM_139_38_centos ~]# ps -ef | grep php
root 26355 24175 0 23:17 pts/0 00:00:00 php pcntl2.php
root 26356 26355 3 23:17 pts/0 00:00:00 php pcntl2.php
root 26357 26355 5 23:17 pts/0 00:00:00 php pcntl2.php
root 26358 26355 3 23:17 pts/0 00:00:00 php pcntl2.php
root 27078 24819 0 23:17 pts/4 00:00:00 grep --color=auto php
root 27079 26357 0 23:17 pts/0 00:00:00 php pcntl2.php
root 27080 26358 0 23:17 pts/0 00:00:00 php pcntl2.php
root 27081 26356 0 23:17 pts/0 00:00:00 php pcntl2.php

单子进程

<?php

$pid = pcntl_fork();

if ($pid == -1) {
die('could not fork');
} elseif ($pid) {
pcntl_wait($status);
} else {
while(1) {
sleep(1);
echo time();
}
}

PHP 实现并发-进程控制 PCNTL的更多相关文章

  1. Linux C 程序 进程控制(17)

    进程控制 1.进程概述现代操作系统的特点在于程序的并行执行.Linux是一个多用户多任务的操作系统.ps .pstree 查看进程进程除了进程id外还有一些其他标识信息,可以通过相应的函数获得.// ...

  2. Linux Shell多进程并发以及并发数控制

    1. 基础知识准备 1.1. linux后台进程 Unix是一个多任务系统,允许多用户同时运行多个程序.shell的元字符&提供了在后台运行不需要键盘输入的程序的方法.输入命令后,其后紧跟&a ...

  3. linux 命令及进程控制

    main.c  main.o/main.obj  main/main.exe          编译                连接 程序运行;      两步: gcc/g++  -c  mai ...

  4. Linux网络编程学习(二) ----- 进程控制(第三章)

    1.进程和程序 程序是一个可执行文件,而一个进程是一个执行中的程序实例.一个进程对应于一个程序的执行,进程是动态的,程序是静态的,多个进程可以并发执行同一个程序.比如几个用户可以同时运行一个编辑程序, ...

  5. 进程控制(Note for apue and csapp)

    1. Introduction We now turn to the process control provided by the UNIX System. This includes the cr ...

  6. UNIX环境高级编程 第8章 进程控制

    本章是UNIX系统中进程控制原语,包括进程创建.执行新程序.进程终止,另外还会对进程的属性加以说明,包括进程ID.实际/有效用户ID. 进程标识 每个进程某一时刻在系统中都是独一无二的,它们之间是用一 ...

  7. Yuchuan_Linux_C 编程之十 进程及进程控制

    一.整体大纲 二.基础知识 1. 进程相关概念 1)程序和进程 程序,是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu.内存.打开的文件.设备.锁....)     进程,是一个抽象的概念,与 ...

  8. 【av68676164(p18-p20)】进程控制

    4.2.1 进程控制的概念 进程控制的概念 在进程生存全期间,对其全部行为的控制 存在四个典型的控制行为 创建进程 阻塞进程 撤销进程 唤醒进程 进程创建 功能:创建一个具有制定标识(ID)的进程 参 ...

  9. Linux&c 文件操作,线程进程控制,网络编程,简单知识点梳理

    一:文件操作 在linux下,一切皆文件,目录是文件,称为目录文件,内容是该目录的目录项(但是目录只有内核可以编辑,超级用户也不可以编辑),设备也是设备文件,在/dev存放的就是一些设备文件,linu ...

随机推荐

  1. android——屏幕适配

    一,基本概念 1:dip: 其实也就是dp,与像素无关 2:px: 像素,在安卓布局中不用px,因为每个手机像素不同,px显示的布局大小也就不同 3:dpi: 通俗点就是每英寸多少个像素,简称像素密度 ...

  2. Apache 的 php.ini 配置文件详解

    [root@taokey ~]# grep -v ";" /application/php/lib/php.ini [PHP] engine = On  ——→  是否启用 PHP ...

  3. 关于jsp删除成功,添加成功等之后 页面自动跳转的js写法

    因为比较常用,所以写在博客里保存起来,防止以后忘了不会写了: 删除成功,<span id="time" style="background:red"> ...

  4. qt console 控制台程序 与win console控制台程序是不同的

    #include <QtCore/QCoreApplication> int main(int argc, char *argv[]){ QCoreApplication a(argc, ...

  5. vue-router解析,vue-router原理解析

    前言:新一季面试季,重新整理一些知识点: 本文详细说明自己对vue-router原理的理解: 参考: 源码:vuejs/vue-router v2.2.1 - github 文档:vue-router ...

  6. @Component和@Bean以及@Autowired、@Resource

    1. 有这么一个故事,从xml配置文件的bean说起   Spring用xml配置文件的时候(不知道阅读这篇文章的你用没用过,我用过一段时间,那是黑暗伤痛的回忆QQQ),一个xml配置文件里面有很多个 ...

  7. 【NOIP2016提高组A组7.16】第三条跑道

    题目 数据范围 分析 时限5000ms. 我们注意到\(a_{i}初始值以及x小于等于600且非零\) 也就是说,\(a_{i}\)的质因数一定小于600,而600以内的质因数只有109个. 那么考虑 ...

  8. 【leetcode】Champagne Tower

    题目如下: 解题思路:本题如果用递归来做,思路会非常清晰.每个杯子得到的总的香槟的数量,减去自身杯子容量后,多余的部分均分成两部分,下层的两个杯子各得一半,但是这种解法在输入香槟较大的情况下会导致超时 ...

  9. 利用Django框架实现分页 demo

  10. luogu 2491 [SDOI2011]消防 / 1099 树网的核 单调队列 + 树上问题

    Code: #include<bits/stdc++.h> #define ll long long #define maxn 300001 #define inf 1000000000 ...