php 的多进程操作实践案例分析
发布:smiling 来源: PHP粉丝网 添加日期:2022-02-15 10:38:17 浏览: 评论:0
本文实例讲述了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的数据。
Tags: php多进程
- 上一篇:php的无刷新操作实现方法分析
- 下一篇:最后一页
相关文章
- ·PHP多进程编程实例说明(2014-01-17)
- ·php多进程几个例子(2014-06-17)
- ·PHP的pcntl多进程用法实例(2021-05-17)
- ·深入探究PHP的多进程编程方法(2021-06-16)
- ·以实例全面讲解PHP中多进程编程的相关函数的使用(2021-06-16)
- ·php多进程模拟并发事务产生的问题小结(2021-11-02)
- ·php多进程应用场景实例详解(2021-12-06)
- ·PHP基于swoole多进程操作示例(2021-12-10)
- ·PHP 多进程与信号中断实现多任务常驻内存管理实例方法(2021-12-27)
- ·PHP多进程简单实例小结(2022-01-21)
- ·php 多进程编程父进程的阻塞与非阻塞实例分析(2022-02-13)
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)