PHP的多进程原理是什么,实际怎样应用
Admin 2022-08-25 群英技术资讯 222 次浏览
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的数据。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
今天小编就为大家分享一篇关于PHP的mysqli_sqlstate()函数讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
本栏目介绍php7安装 pdo_mysql 扩展,有需要的朋友可以看看,了解了解。
本篇文章小编给大家分享一下Python类与实例代码使用解析,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
laravel怎样实现批量更新数据?我们知道Laravel框架中有批量插入数据的方法,但是没有批量更新的方法,如果要每条数据都执行一次,那么不仅速度慢而且会占用更多的资源。对此,这篇文章就给大家分享一下laravel实现批量更新多条数据的方法。
本文实例讲述了PHP设计模式:适配器模式Adapter。分享给大家供大家参考,具体如下:
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008