zoukankan      html  css  js  c++  java
  • php 的多进程

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

    例子1:

     1 <?php
     2 $pid = pcntl_fork();
     3  
     4 if($pid == -1) {
     5     //错误处理:创建子进程失败时返回-1.
     6     die('fork error');
     7 } else if ($pid) {
     8     //父进程会得到子进程号,所以这里是父进程执行的逻辑
     9     echo "parent 
    ";
    10     //等待子进程中断,防止子进程成为僵尸进程。
    11     pcntl_wait($status);
    12 } else {
    13     //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
    14     echo "child 
    ";
    15  
    16     exit;
    17 }

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

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

    例子2:

     1 <?php
     2 $pid = pcntl_fork();
     3  
     4 if($pid == -1) {
     5     die('fork error');
     6 } else if ($pid) {
     7     sleep(3);
     8     echo "parent 
    ";
     9     pcntl_wait($status);
    10 } else {
    11     echo "child 
    ";
    12  
    13     exit;
    14 }

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

     那么问题又来了?pcntl_wait是做什么用的?

    会挂起当前进程,直到子进程退出,如果子进程在调用此函数之前就已退出,此函数会立刻返回。子进程使用的资源将被释放。

    例子3:

     1 <?php
     2 $pid = pcntl_fork();
     3  
     4 if($pid == -1) {
     5     die('fork error');
     6 } else if ($pid) {
     7     pcntl_wait ($status);
     8     echo "parent 
    ";
     9 } else {
    10     sleep(3);
    11     echo "child 
    ";
    12  
    13     exit;
    14 }

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

    例子4:

     1 <?php
     2 define('FORK_NUMS', 3);
     3  
     4 $pids = array();
     5  
     6 for($i = 0; $i < FORK_NUMS; ++$i) {
     7     $pids[$i] = pcntl_fork();
     8     if($pids[$i] == -1) {
     9         die('fork error');
    10     } else if ($pids[$i]) {
    11         pcntl_waitpid($pids[$i], $status);
    12         echo "pernet 
    ";
    13     } else {
    14         sleep(3);
    15         echo "child id:" . getmypid() . " 
    ";
    16         exit;
    17     }
    18 }

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

    输出结果如下:

    例子5:

     1 <?php
     2 define('FORK_NUMS', 3);
     3  
     4 $pids = array();
     5  
     6 for($i = 0; $i < FORK_NUMS; ++$i) {
     7     $pids[$i] = pcntl_fork();
     8     if($pids[$i] == -1) {
     9         die('fork error');
    10     } else if ($pids[$i]) {
    11  
    12     } else {
    13         sleep(3);
    14         echo "child id:" . getmypid() . " 
    ";
    15         exit;
    16     }
    17 }
    18  
    19 foreach($pids as $k => $v) {
    20     if($v) {
    21         pcntl_waitpid($v, $status);
    22         echo "parent 
    ";
    23     }
    24 }

    输出结果:

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

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

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

    例子6:

     1 <?php
     2  
     3 define('FORK_NUMS', 3);
     4  
     5 $pids = array();
     6  
     7 $fp = fopen('./test.log', 'wb');
     8 $num = 1;
     9  
    10 for($i = 0; $i < FORK_NUMS; ++$i) {
    11     $pids[$i] = pcntl_fork();
    12     if($pids[$i] == -1) {
    13         die('fork error');
    14     } else if ($pids[$i]) {
    15  
    16  
    17     } else {
    18         for($i = 0; $i < 5; ++$i) {
    19  
    20             flock($fp, LOCK_EX);
    21             fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {$num} 
    ");
    22  
    23             flock($fp, LOCK_UN);
    24             echo getmypid(), ": success 
    ";
    25             ++$num;
    26         }
    27         exit;
    28     }
    29 }
    30  
    31 foreach($pids as $k => $v) {
    32     if($v) {
    33         pcntl_waitpid($v, $status);
    34     }
    35 }
    36  
    37 fclose($fp);

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

    如何在进程中共享数据?

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

    例子7:

     1 <?php
     2  
     3 define('FORK_NUMS', 3);
     4  
     5 $pids = array();
     6  
     7 $fp = fopen('./test.log', 'wb');
     8 $num = 1;
     9 //共享内存段的key
    10 $shmKey = 123;
    11 //创建共享内存段
    12 $shmId = shmop_open($shmKey, 'c', 0777, 64);
    13 //写入数据到共享内存段
    14 shmop_write($shmId, $num, 0);
    15  
    16 for($i = 0; $i < FORK_NUMS; ++$i) {
    17     $pids[$i] = pcntl_fork();
    18     if($pids[$i] == -1) {
    19         die('fork error');
    20     } else if ($pids[$i]) {
    21  
    22         //阻塞,等待子进程退出
    23  
    24         //注意这里,如果是非阻塞的话,$num的计数会出现问题。
    25         pcntl_waitpid($pids[$i], $status);
    26     } else {
    27         //读取共享内存段中的数据
    28         $num = shmop_read($shmId, 0, 64);
    29         for($i = 0; $i < 5; ++$i) {
    30             fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {$num} 
    ");
    31             echo getmypid(), ": success 
    ";
    32             //递增$num
    33             $num = intval($num) + 1;
    34         }
    35  
    36         //写入到共享内存段中
    37  
    38         shmop_write($shmId, $num, 0);
    39         exit;
    40     }
    41 }
    42  
    43 //shmop_delete不会实际删除该内存段,它将该内存段标记为删除。
    44 shmop_delete($shmId);
    45 shmop_close($shmId);
    46 fclose($fp);

    最后结果:

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

  • 相关阅读:
    登录注册页面切换
    LINUX系统日常使用命令
    find命令详解
    ssh命令详解
    tar命令详解
    route命令详解
    uname命令详解
    ps命令详解
    df命令详解
    virsh命令详解
  • 原文地址:https://www.cnblogs.com/setevn/p/8598000.html
Copyright © 2011-2022 走看看