参考 基于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数据库使用指南(上)

    前言Android上的数据库是sqlite,虽然这个数据库是轻量级的,但是储存的东西可不少,sqlite官方表示理论存储容量为140TB,目前应该没有那么大容量的手机,存储能力太强了. 关于如何使用S ...

  2. 远程连接mysql出现1130的错误

    数据库权限不足 连接数据以后执行以下命令 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '您的数据库密码' WITH GRANT OP ...

  3. Vue获取dom元素

     <li  @click='获取li标签'    :ref="center-li" id="center-li"      > =====我是li标 ...

  4. git log混乱之混乱操作

    好几个分支 然后就混乱了 git log信息一坨屎 git 删除某次指定的提交 git reset只是在本地仓库中回退版本,而远程仓库的版本不会变化. 以删除master分支为例 #新建一个备份的分支 ...

  5. Azure IoT 技术研究系列2

    上篇博文中,我们主要介绍了Azure IoT Hub的基本概念.架构.特性: Azure IoT 技术研究系列1-入门篇 本文中,我们继续深入研究,做一个起步示例程序:模拟设备注册到Azure IoT ...

  6. sqlserver 2012 中的 sysobjects

    sysobjects 表  在数据库内创建的每个对象(约束.默认值.日志.规则.存储过程等)在表中占一行

  7. React 之React.createContext

    使用Context,可以跨越组件进行数据传递 import React from 'react'; import ReactDOM from 'react-dom'; const ThemeConte ...

  8. Java——this

    [this] 在没有new一个对象前,this不知道指的是什么:当new出一个对象时,this指的是当前对象的引用.  

  9. VS2019界面透明、主题修改和导出设置

    目录 安装插件Color Theme Editor for Visual Studio 2019和ClaudiIDE 导入主题 背景修改 效果预览 导出设置遇到错误924 其他帮助文档 我自己用的主题 ...

  10. 前端HTTP缓存

    Web 缓存大致可以分为:数据库缓存.服务器端缓存(代理服务器缓存.CDN 缓存).浏览器缓存.其中前端比较关心的是浏览器缓存,包括今天要说的HTTP缓存和前面说过的cookie.localStora ...