当前位置:首页 > PHP > 正文内容

【一】PHP多进程学习-简单创建父子进程.理解父子进程运行流程

高老师8年前 (2019-04-04)PHP1677

(1).学习的目标:

学会创建父子进程,并且能够区分当前进程是父还是子;了解父进程执行过程,子进程执行过程;能够用多进程执行任务

(2).相关函数学习:

    (2.1)pcntl_fork()执行时:
         如果当前的进程是父进程执行这个函数会返回创建成功的子进程的PID
         如果当前的进程是子进程且第一次执行这个函数会返回0,第二次执行会返回创建成功的子进程PID
         无论当前执行本函数的是父进程还是子进程,创建失败均返回-1
         延伸:通过本函数的返回值我们可以认为,返回值-1是创建进程失败,大于0说明当前的进程是父进程,等于0说明当前的进程是子进程;本函数执行成功,底层会启动一个子进程从头开始再运行当前的脚本代码.
    (2.2)cli_set_process_title()函数用于设置当前进程的标题,可以在终端查看    

    (2.3)pcntl_wait()函数内部通过挂起当前进程来等待子进程的状态.根据子进程的状态来决定父进程是否继续执行还是等待
         例子:pcntl_wait($status)的意思是父进程必须等待一个子进程退出后,才能继续向下执行.pcntl_wait($status, WNOHANG);的是意思子进程没有退出父进程也可以继续向下执行。

(3).代码案例
    (3.1).创建一个阻塞的子进程

<?php
//获取当前进程的Pid
$ppid = posix_getpid();

//创建子进程
$pid = pcntl_fork();
if ($pid == -1)
{
    die ('创建子进程失败' . PHP_EOL);
}
elseif ($pid > 0)
{
    cli_set_process_title("demo:我是父,我的id是{$ppid}");
    sleep(30);
    pcntl_wait($status);//父进程必须等待一个子进程退出后,才能继续走
}
else
{
    $cpid = posix_getpid();
    cli_set_process_title("demo:我是子,我的id是{$cpid}");
    //子进程可以在这里执行部分任务
    sleep(5);
}

解析: 执行顺序为父进程创建子进程,父进程一直挂起在elseif代码区域等子进程执行完成再继续往下走,子进程执行完成,父进程结束

父进程的执行:
    父进程调用pcntl_fork()创建了一个子进程,linux底层创建一个新的子进程让它重新跑一遍当前的代码(看子进程的执行说明)
    父进程调用pcntl_fork()成功会返回一个大于0的子进程id,所以会执行到$pid>0代码区域,父进程发现pcntl_wait($status)代码让他等刚才创建的子进程把代码跑完他才能向下执行,于是父进程一直卡在这里睡觉等.

子进程的执行:
    子进程调用pcntl_fork()创建子进程,一定是返回0,因为它自己就是子进程,所以没法再创建.$pid返回0则执行到子进程的代码区域,子进程sleep5秒后执行完成了.
      
父进程的执行:
    刚才的父进程一直卡在父进程区域等子进程执行完成,现在子进程执行完成了,父进程继续向下执行,直到结束。

    (3.2).循环创建多个非阻塞的子进程

for ($i = 0; $i < 3; $i++)
{
    //创建子进程
    $pid = pcntl_fork();
    if ($pid == -1)
    {
        die ('创建子进程失败' . PHP_EOL);
    }
    elseif ($pid > 0)
    {
        cli_set_process_title("demo:我是父,我的id是{$ppid}");
        pcntl_wait($status, WNOHANG); //我不管你子进程是否执行完成,我继续循环创建下一个子进程
    }
    else
    {
        $cpid = posix_getpid();
        cli_set_process_title("demo:我是子,我的id是{$cpid}");
        
        //可以在这里加上任务处理数据
        
        sleep(10);
        die();
    }
}

解析: 执行顺序为父进程创建完成3个子进程,然后父进程退出程序,剩下3个子进程在运行,每个子进程也只能循环1次,因为在循环中判断是子进程最后使用die结束了,为什么要加die?因为在上面的函数介绍中说明了子进程执行pcntl_fork函数第一次不会创建子进程,如果不die每个子进程还要循环3次,重复一堆子进程.

父进程的执行:

    父进程调用pcntl_fork创建了一个子进程,底层创建一个新的子进程让它重新跑一遍当前的代码

    父进程调用pcntl_fork()成功会返回一个大于0的子进程id,所以会执行到$pid>0代码区域,父进程发现pcntl_wait($status, WNOHANG)代码让他继续创建子进程,全部创建完成后父进程退出.

子进程的执行:

    子进程调用pcntl_fork创建子进程,一定是返回0,因为它自己就是子进程,所以没法再创建.$pid返回0则执行到子进程的代码区域,子进程sleep5秒后会继续执行剩余的循环,所以这里在子进程加了die

其他:有人会问如果我需要子进程一直程序处理任务,但是这里die了子进程。这里使用die的目的是防止子进程继续循环创建重复的进程,如果想让子进程一直处理任务可以加while(true);上面的代码中使用sleep函数是为了程序多运行一会儿,方便在linux中看到进程的标题;

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

版权声明:本文由高久峰个人博客发布,如需转载请注明出处。

本文链接:https://blog.20230611.cn/post/83.html

分享给朋友:

“【一】PHP多进程学习-简单创建父子进程.理解父子进程运行流程” 的相关文章

PHP生成微信分享需要的signature签名

PHP生成微信分享需要的signature签名

因为一个TP项目中客户需要全部网页分享支持自定义图片和描述信息,于是自己封装了下 //share()微信分享链接 //参数1 appid //参数2 appsert //参数3 nonceStr随机码 //参数4 timestamp时间戳 public&nb...

PHP最快方式模拟curl,PHP最快爬虫模拟方法

PHP最快方式模拟curl,PHP最快爬虫模拟方法

有时候我们需要爬一个接口,但是这个接口需要很多参数,包括header和cookie要去编写,使用php curl模拟实在太慢。我们可以通过浏览器的network来复制请求为curl命令。例如我需要模拟请求接口地址:https://www.xkmz.cc/Ajax/Debug/delly,我们只需要在...

php elasticsearch基础使用

php elasticsearch基础使用

elasticsearch的操作都是基于http协议的,已经有现成的php类库,composer安装即可。{     "require": {        &...

windows安装php event扩展问题

windows安装php event扩展问题

php event扩展在windows中依赖于php_sockets扩展,因此在php.ini中必须先加载php sockets扩展,如下。extension=sockets extension=event...

php redis队列实现秒杀 , php用redis 实现秒杀功能

php redis队列实现秒杀 , php用redis 实现秒杀功能

为什么使用队列?因为pop取队列具有原子性。假如我们需要秒杀一个商品id,我们先将商品的库存保存到一个队列。例如:<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6...

php位运算符详解

php位运算符详解

文章篇幅较长,如果不喜欢看文章的,此处抛出韩顺丰老师的位运算视频,韩老师应该是全网讲php位运算符最详细的一个老师了。链接:https://pan.baidu.com/s/14xj7er8eVSUcJ-jYXyA0GA  提取码:731m 链接:https://pan.baidu.com...