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

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

    本文实例讲述了php 的多进程操作。分享给大家供大家参考,具体如下:

    php的多进程处理依赖于pcntl扩展,通过pcntl_fork创建子进程来进行并行处理。

    例1如下:

    ?php
    $pid = pcntl_fork();
    
    if($pid == -1) {
      //错误处理:创建子进程失败时返回-1.
      die('fork error');
    } else if ($pid) {
      //父进程会得到子进程号,所以这里是父进程执行的逻辑
      echo "parent \n";
      //等待子进程中断,防止子进程成为僵尸进程。
      pcntl_wait($status);
    } else {
      //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
      echo "child \n";
    
      exit;
    }
    
    

    pcntl_fork创建了子进程,父进程和子进程都继续向下执行,而不同是父进程会获取子进程的$pid也就是$pid不为零。而子进程会获取$pid为零。通过if else语句判断$pid我们就可以在指定位置写上不同的逻辑代码。

    上述代码会分别输出parent和child。那么输出的parent和child是否会有顺序之分?是父进程会先执行?

    例2如下:

    ?php
    $pid = pcntl_fork();
    
    if($pid == -1) {
      die('fork error');
    } else if ($pid) {
      sleep(3);
      echo "parent \n";
      pcntl_wait($status);
    } else {
      echo "child \n";
    
      exit;
    }
    
    

    我们在父进程中通过sleep来延缓执行,看看效果。

    结果是,很快输出了child,等待了接近3秒后,才输出parent。所以父进程和子进程的执行是相对独立的,没有先后之分。

    那么问题又来了?pcntl_wait是做什么用的?
    会挂起当前进程,直到子进程退出,如果子进程在调用此函数之前就已退出,此函数会立刻返回。子进程使用的资源将被释放。

    例3如下:

    ?php
    $pid = pcntl_fork();
    
    if($pid == -1) {
      die('fork error');
    } else if ($pid) {
      pcntl_wait ($status);
      echo "parent \n";
    } else {
      sleep(3);
      echo "child \n";
    
      exit;
    }
    
    

    上述代码,我们可以看到,父进程执行pcntl_wait时就已经挂起,直到等待3秒后输出child,子进程退出后。父进程继续执行,输出parent。

    例4如下:

    ?php
    define('FORK_NUMS', 3);
    
    $pids = array();
    
    for($i = 0; $i  FORK_NUMS; ++$i) {
      $pids[$i] = pcntl_fork();
      if($pids[$i] == -1) {
        die('fork error');
      } else if ($pids[$i]) {
        pcntl_waitpid($pids[$i], $status);
        echo "pernet \n";
      } else {
        sleep(3);
        echo "child id:" . getmypid() . " \n";
        exit;
      }
    }
    
    

    上述代码,我们创建3个子进程,父进程分别挂起等待子进程结束后,输出parent。

    输出结果如下:

    child id:19090
    pernet
    child id:19091
    pernet
    child id:19092
    pernet

    例5如下:

    ?php
    define('FORK_NUMS', 3);
    
    $pids = array();
    
    for($i = 0; $i  FORK_NUMS; ++$i) {
      $pids[$i] = pcntl_fork();
      if($pids[$i] == -1) {
        die('fork error');
      } else if ($pids[$i]) {
    
      } else {
        sleep(3);
        echo "child id:" . getmypid() . " \n";
        exit;
      }
    }
    
    foreach($pids as $k => $v) {
      if($v) {
        pcntl_waitpid($v, $status);
        echo "parent \n";
      }
    }
    
    

    输出结果如下:

    child id:19118
    child id:19119
    child id:19120
    parent
    parent
    parent

    为什么上述代码跟例4的输出结果不一样?

    我们可以看到例5的pcntl_waitpid函数放在了foreach中,foreach代码是在主进程中,也就是父进程的代码中。当执行foreach时,可能子进程已经全部执行完毕并退出。pcntl_waitpid会立刻返回,连续输出三个parent。

    (*在子进程中,需通过exit来退出,不然会产生递归多进程,父进程中不需要exit,不然会中断多进程。)

    例6如下:

    ?php
    define('FORK_NUMS', 3);
    
    $pids = array();
    
    $fp = fopen('./test.log', 'wb');
    $num = 1;
    
    for($i = 0; $i  FORK_NUMS; ++$i) {
      $pids[$i] = pcntl_fork();
      if($pids[$i] == -1) {
        die('fork error');
      } else if ($pids[$i]) {
    
    
      } else {
        for($i = 0; $i  5; ++$i) {
    
          flock($fp, LOCK_EX);
          fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {$num} \r\n");
    
          flock($fp, LOCK_UN);
          echo getmypid(), ": success \r\n";
          ++$num;
        }
        exit;
      }
    }
    
    foreach($pids as $k => $v) {
      if($v) {
        pcntl_waitpid($v, $status);
      }
    }
    
    fclose($fp);
    
    

    代码如上:我们创建三个子进程,来同时向test.log文件写入内容,test.log内容如下:

    19507 : 2016-03-16 20:40:52 : 1
    19507 : 2016-03-16 20:40:52 : 2
    19507 : 2016-03-16 20:40:52 : 3
    19507 : 2016-03-16 20:40:52 : 4
    19507 : 2016-03-16 20:40:52 : 5
    19509 : 2016-03-16 20:40:52 : 1
    19509 : 2016-03-16 20:40:52 : 2
    19509 : 2016-03-16 20:40:52 : 3
    19509 : 2016-03-16 20:40:52 : 4
    19509 : 2016-03-16 20:40:52 : 5
    19508 : 2016-03-16 20:40:52 : 1
    19508 : 2016-03-16 20:40:52 : 2
    19508 : 2016-03-16 20:40:52 : 3
    19508 : 2016-03-16 20:40:52 : 4
    19508 : 2016-03-16 20:40:52 : 5

    我们可以看到三个子进程的pid,它们分别执行了5次,时间几乎是在同时。但是$num的值并没像我们期望的那样从1-15进行递增。子进程中的变量是各自独立的,互不影响。子进程会自动复制父进程空间里的变量。

    如何在进程中共享数据?

    我们通过php的共享内存函数shmop来实现。

    ?php
    define('FORK_NUMS', 3);
    
    $pids = array();
    
    $fp = fopen('./test.log', 'wb');
    $num = 1;
    //共享内存段的key
    $shmKey = 123;
    //创建共享内存段
    $shmId = shmop_open($shmKey, 'c', 0777, 64);
    //写入数据到共享内存段
    shmop_write($shmId, $num, 0);
    
    for($i = 0; $i  FORK_NUMS; ++$i) {
      $pids[$i] = pcntl_fork();
      if($pids[$i] == -1) {
        die('fork error');
      } else if ($pids[$i]) {
    
        //阻塞,等待子进程退出
    
        //注意这里,如果是非阻塞的话,$num的计数会出现问题。
        pcntl_waitpid($pids[$i], $status);
      } else {
        //读取共享内存段中的数据
        $num = shmop_read($shmId, 0, 64);
        for($i = 0; $i  5; ++$i) {
          fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {$num} \r\n");
          echo getmypid(), ": success \r\n";
          //递增$num
          $num = intval($num) + 1;
        }
    
        //写入到共享内存段中
    
        shmop_write($shmId, $num, 0);
        exit;
      }
    }
    
    //shmop_delete不会实际删除该内存段,它将该内存段标记为删除。
    shmop_delete($shmId);
    shmop_close($shmId);
    fclose($fp);
    
    

    上述代码的运行结果如下:

    19923 : 2016-03-17 00:05:18 : 1
    19923 : 2016-03-17 00:05:18 : 2
    19923 : 2016-03-17 00:05:18 : 3
    19923 : 2016-03-17 00:05:18 : 4
    19923 : 2016-03-17 00:05:18 : 5
    19924 : 2016-03-17 00:05:18 : 6
    19924 : 2016-03-17 00:05:18 : 7
    19924 : 2016-03-17 00:05:18 : 8
    19924 : 2016-03-17 00:05:18 : 9
    19924 : 2016-03-17 00:05:18 : 10
    19925 : 2016-03-17 00:05:18 : 11
    19925 : 2016-03-17 00:05:18 : 12
    19925 : 2016-03-17 00:05:18 : 13
    19925 : 2016-03-17 00:05:18 : 14
    19925 : 2016-03-17 00:05:18 : 15

    这样我们就在进程间共享了$num的数据。

    更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP进程与线程操作技巧总结》、《PHP网络编程技巧总结》、《PHP基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

    希望本文所述对大家PHP程序设计有所帮助。

    您可能感兴趣的文章:
    • php多进程中的阻塞与非阻塞操作实例分析
    • php多进程并发编程防止出现僵尸进程的方法分析
    • php 多进程编程父进程的阻塞与非阻塞实例分析
    • php实现的简单多进程服务器类完整示例
    • PHP多进程简单实例小结
    • PHP 多进程与信号中断实现多任务常驻内存管理实例方法
    • php swoole多进程/多线程用法示例【基于php7nts版】
    • PHP基于swoole多进程操作示例
    • 详解PHP多进程消费队列
    上一篇:php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
    下一篇:php多进程并发编程防止出现僵尸进程的方法分析
  • 相关文章
  • 

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

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

    php 的多进程操作实践案例分析 php,的,多,进程,操作,实践,