(1).学习的目标:
学会创建父子进程,并且能够区分当前进程是父还是子;了解父进程执行过程,子进程执行过程;能够用多进程执行任务
(2).相关函数学习:
(2.1)pcntl_fork()执行时:
如果当前的进程是父进程执行这个函数会返回创建成功的子进程的PID
如果当前的进程是子进程且第一次执行这个函数会返回0,第二次执行会返回创建成功的子进程PID
无论当前执行本函数的是父进程还是子进程,创建失败均返回-1
延伸:通过本函数的返回值我们可以认为,返回值-1是创建进程失败,大于0说明当前的进程是父进程,等于0说明当前的进程是子进程;本函数执行成功,底层会启动一个子进程从头开始再运行当前的脚本代码.
(2.2)cli_set_process_title()函数用于设置当前进程的标题,可以在终端查看
(2.3)pcntl_wait()函数内部通过挂起当前进程来等待子进程的状态.根据子进程的状态来决定父进程是否继续执行还是等待
例子:pcntl_wait($status)的意思是父进程必须等待一个子进程退出后,才能继续向下执行.pcntl_wait($status, WNOHANG);的是意思子进程没有退出父进程也可以继续向下执行。
(3).代码案例
(3.1).创建一个阻塞的子进程
<?php //获取当前进程的Pid $ppid = posix_getpid(); //创建子进程 $pid = pcntl_fork(); if ($pid == -1) { die ('创建子进程失败' . PHP_EOL); } elseif ($pid > 0) { cli_set_process_title("demo:我是父,我的id是{$ppid}"); sleep(30); pcntl_wait($status);//父进程必须等待一个子进程退出后,才能继续走 } else { $cpid = posix_getpid(); cli_set_process_title("demo:我是子,我的id是{$cpid}"); //子进程可以在这里执行部分任务 sleep(5); }
解析: 执行顺序为父进程创建子进程,父进程一直挂起在elseif代码区域等子进程执行完成再继续往下走,子进程执行完成,父进程结束
父进程的执行:
父进程调用pcntl_fork()创建了一个子进程,linux底层创建一个新的子进程让它重新跑一遍当前的代码(看子进程的执行说明)
父进程调用pcntl_fork()成功会返回一个大于0的子进程id,所以会执行到$pid>0代码区域,父进程发现pcntl_wait($status)代码让他等刚才创建的子进程把代码跑完他才能向下执行,于是父进程一直卡在这里睡觉等.
子进程的执行:
子进程调用pcntl_fork()创建子进程,一定是返回0,因为它自己就是子进程,所以没法再创建.$pid返回0则执行到子进程的代码区域,子进程sleep5秒后执行完成了.
父进程的执行:
刚才的父进程一直卡在父进程区域等子进程执行完成,现在子进程执行完成了,父进程继续向下执行,直到结束。
(3.2).循环创建多个非阻塞的子进程
for ($i = 0; $i < 3; $i++) { //创建子进程 $pid = pcntl_fork(); if ($pid == -1) { die ('创建子进程失败' . PHP_EOL); } elseif ($pid > 0) { cli_set_process_title("demo:我是父,我的id是{$ppid}"); pcntl_wait($status, WNOHANG); //我不管你子进程是否执行完成,我继续循环创建下一个子进程 } else { $cpid = posix_getpid(); cli_set_process_title("demo:我是子,我的id是{$cpid}"); //可以在这里加上任务处理数据 sleep(10); die(); } }
解析: 执行顺序为父进程创建完成3个子进程,然后父进程退出程序,剩下3个子进程在运行,每个子进程也只能循环1次,因为在循环中判断是子进程最后使用die结束了,为什么要加die?因为在上面的函数介绍中说明了子进程执行pcntl_fork函数第一次不会创建子进程,如果不die每个子进程还要循环3次,重复一堆子进程.
父进程的执行:
父进程调用pcntl_fork创建了一个子进程,底层创建一个新的子进程让它重新跑一遍当前的代码
父进程调用pcntl_fork()成功会返回一个大于0的子进程id,所以会执行到$pid>0代码区域,父进程发现pcntl_wait($status, WNOHANG)代码让他继续创建子进程,全部创建完成后父进程退出.
子进程的执行:
子进程调用pcntl_fork创建子进程,一定是返回0,因为它自己就是子进程,所以没法再创建.$pid返回0则执行到子进程的代码区域,子进程sleep5秒后会继续执行剩余的循环,所以这里在子进程加了die
其他:有人会问如果我需要子进程一直程序处理任务,但是这里die了子进程。这里使用die的目的是防止子进程继续循环创建重复的进程,如果想让子进程一直处理任务可以加while(true);上面的代码中使用sleep函数是为了程序多运行一会儿,方便在linux中看到进程的标题;
<?php /* * 单粒模式,只能造出一个对象 1.肯定每次new只能返回一个对象,可以使用静态方法解决 2.子类继承也禁止重写构造方法,添加final搞定 * */ ...
前面的文章对于高并发下单商品导致商品库存为负值的问题请先阅读再阅读本篇文章一定对您有帮助,建议亲手测试较好。加上文件锁后的下单处理代码:【一】.阻塞模式:(如果其他进程已经加锁文件,当前进程会一直等其他进程解锁文件后继续执行)<?php //连接数据库 $con=mysqli_connect(...
<?php $member = new class { public function getInfo() { ...
<?php /** * @throws Exception */ function curl() { throw new \Exception('err...
今天帮朋友查询wordpress执行超级慢的原因,特此记录开启fpm的慢日志,记录执行超过30秒的脚本request_slowlog_timeout = 30 slowlog = var/log/slow.log查看日志[23-May-2019 17...
php7.1引入了PHP异步信号处理函数pcntl_async_signals() 来处理阻塞问题。在php7之前信号处理方式有2种,第一种是基于ticks来每执行一行代码来触发执行信号监听,第二种是直接while(true){ //监听信号 }第一种方式如果某行的代码阻塞时间较长会影响...