• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    浅析PHP7的多进程及实例源码

    准备

    我们都知道PHP是单进程执行的,PHP处理多并发主要是依赖服务器或PHP-FPM的多进程及它们进程的复用,但PHP实现多进程也意义重大,尤其是在后台Cli模式下处理大量数据或运行后台DEMON守护进程时,多进程的优势不用多说。

    PHP的多线程也曾被人提及,但进程内多线程资源共享和分配的问题难以解决。PHP也有多线程想关的扩展 pthreads ,但据说不太稳定,且要求环境为线程安全,所用不多。

    以前PHP群里的一位大神曾指导说后台PHP想进阶必然避不开多进程,正好公司里的守护进程也应用了PHP的多进程,结合着谷哥的各种资料和手册,总算理解了多进程,并自己写了一个小demo(在linux系统上实现的),用此文总结一下,如有错漏,谢谢提出。

    要实现PHP的多进程,我们需要两个扩展 pcntl 和 posix,安装方法这里不再赘述。

    在php中我们使用pcntl_fork()来创建多进程(在*NIX系统的C语言编程中,已有进程通过调用fork函数来产生新的进程)。fork出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。这里要注意:

    • 子进程与父进程共享程序正文段

    • 子进程拥有父进程的数据空间和堆、栈的副本,注意是副本,不是共享

    • 父进程和子进程将继续执行fork之后的程序代码

    • fork之后,是父进程先执行还是子进程先执行无法确认,取决于系统调度(取决于信仰)

    这里说子进程拥有父进程数据空间以及堆、栈的副本,实际上,在大多数的实现中也并不是真正的完全副本。更多是采用了COW(Copy On Write)即写时复制的技术来节约存储空间。简单来说,如果父进程和子进程都不修改这些 数据、堆、栈 的话,那么父进程和子进程则是暂时共享同一份 数据、堆、栈。只有当父进程或者子进程试图对 数据、堆、栈 进行修改的时候,才会产生复制操作,这就叫做写时复制。

    在调用完pcntl_fork()后,该函数会返回两个值。在父进程中返回子进程的进程ID,在子进程内部本身返回数字0。由于多进程在apache或者fpm环境下无法正常运行,所以大家一定要在php cli环境下执行代码。

    创建子进程

    创建PHP子进程是多进程的开始,我们需要pcntl_fork()函数;

    fork函数详解

    pcntl_fork() — 在当前进程当前位置产生分支(子进程)。此函数创建了一个新的子进程后,子进程会继承父进程当前的上下文,和父进程一样从pcntl_fork() 函数处继续向下执行,只是获取到的pcntl_fork() 的返回值不同,我们便能从判断返回值来区分父进程和子进程,分配父进程和子进程去做不同的逻辑处理。

    pcntl_fork() 函数成功执行时会在父进程返回子进程的进程id(pid),因为系统的初始进程init进程的pid为1,后来产生进程的pid都会大于此进程,所以我们可以通过判断pcntl_fork()的返回值大于1来确实当前进程是父进程;而在子进程中,此函数的返回值会是固定值0,我们也可以通过判断pcntl_fork()的返回值为0来确定子进程;而pcntl_fork()函数在执行失败时,会在父进程返回-1,当然也不会有子进程产生。

    fork进程实例

    fork子进程

    $ppid = posix_getpid();
    
    $pid = pcntl_fork();
    
    if ($pid == -1) {
    
      throw new Exception('fork child process fail');
    
    } elseif ($pid > 0) {
    
      cli_set_process_title("我是父 process,pid is : {$ppid}.");
    
      sleep(30);
    
    } else {
    
      $cpid = posix_getpid();
    
      cli_set_process_title("我是 {$ppid} 子的 process,我的 process pid is : {$cpid}.");
    
      sleep(30);
    
    }

    说明:

    posix_getpid():返回当前进程 id

    cli_set_process_title('进程名称'):为当前进程取一个响亮的名字。

    运行这个例子,我们便能看到当前两个PHP进程了。

    www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ ps aux|grep -v grep |grep 我
    
    www   18026 0.5 1.2 204068 25772 pts/0  S+  14:08  0:00 我是父 process,pid is : 18026.
    
    www   18027 0.0 0.3 204068 6640 pts/0  S+  14:08  0:00 我 18026 子的 process,我的 process pid is : 18027. 

    第一段代码,在程序从pcntl_fork()后父进程和子进程将各自继续往下执行代码:

    $pid = pcntl_fork();
    
    if( $pid > 0 ){
    
     echo "我是父亲".PHP_EOL;
    
    } else if( 0 == $pid ) {
    
     echo "我是儿子".PHP_EOL;
    
    } else {
    
     echo "fork失败".PHP_EOL;
    
    } 

    结果:

    www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ php 123.php
    
    我是父亲
    
    我是儿子

    第二段代码,用来说明子进程拥有父进程的数据副本,而并不是共享:

    // 初始化一个 number变量 数值为1
    
    $number = 1;
    
    $pid = pcntl_fork();
    
    if ($pid > 0) {
    
      $number += 1;
    
      echo "我是父亲,number+1 : { $number }" . PHP_EOL;
    
    } else if (0 == $pid) {
    
      $number += 2;
    
      echo "我是儿子,number+2 : { $number }" . PHP_EOL;
    
    } else {
    
      echo "fork失败" . PHP_EOL;
    
    }

    结果

    www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ php 1234.php
    
    我是父亲,number+1 : { 2 }
    
    我是儿子,number+2 : { 3 }

    您可能感兴趣的文章:
    • PHP多进程通信-消息队列使用
    • PHP 多进程与信号中断实现多任务常驻内存管理实例方法
    • php多进程模拟并发事务产生的问题小结
    • PHP多进程编程之僵尸进程问题的理解
    • PHP多进程编程总结(推荐)
    • PHP的Socket通信之UDP通信实例
    • PHP与Go语言之间的通信详解
    • php中socket通信机制实例详解
    • php实现的简单多进程服务器类完整示例
    上一篇:什么是PHP7中的孤儿进程与僵尸进程
    下一篇:PHP7中I/O模型内核剖析详解
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    浅析PHP7的多进程及实例源码 浅析,PHP7,的,多,进程,及,