多进程的作用是一个程序启动多个进程。
一个程序启动起来本应该是一个进程,但它可作为父进程启动多个子进程来一起操作
形成并发操作
pcntl是php官方的多进程扩展,只能在linux环境使用
以下所有操作请在Linux环境下操作:
先认识两个函数,下面是官方文档地址:
PHP: POSIX - Manual
echo '当前进程的pid:'.posix_getpid()."\n"; // 当前进程的标识PID
echo '当前进程的父进程pid:'.posix_getppid()."\n"; // 当前进程父进程的标识PID
看下图 我们发现程序运行完就打印出来了当前进程标识 和 父进程标识 并且已经运行完成了
接下来我们在程序里面加入一个死循环
echo '当前进程的pid:'.posix_getpid()."\n"; // 当前进程的标识PID
echo '当前进程的父进程pid:'.posix_getppid()."\n"; // 当前进程父进程的标识PID
while(1){
;
}
再次运行
我们再打开一个新的连接 并查看php所有进程
# 查看Linux上的所有php进程
ps -ef | grep php
下一个函数: pcntl_fork
PHP: pcntl_fork - Manual
pcntl_fork — 在当前进程当前位置产生分支(子进程)。译注:fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号,而子进程得到的是0。
官方简介说的已经很清楚了在当前进程当前的位置产生分支( 子进程 )
// 让我们来愉快的学习php的多进程
echo '当前进程的pid:'.posix_getpid()."\n"; // 当前进程的标识PID
echo '当前进程的父进程pid:'.posix_getppid()."\n"; // 当前进程父进程的标识PID
$pid = pcntl_fork(); // 官方说当前fork返回的是子进程的标识PID
echo "我是啥:".$pid."\n";
while(1){
;
}
哪个进程先运行是无法确定的,也是无法知道的,是由操作系统来决定的,它的进程调度由系统决定
当我们不知道系统先调用那个进程的话,这个时候就需要加入判断
// 让我们来愉快的学习php的多进程
echo '当前进程的pid:'.posix_getpid()."\n"; // 当前进程的标识PID
echo '当前进程的父进程pid:'.posix_getppid()."\n"; // 当前进程父进程的标识PID
$pid = pcntl_fork(); // 官方说当前fork返回的是子进程的标识PID
if($pid == -1){
die("开启进程失败!"); // 开启失败
}elseif ($pid == 0){
echo "我是子进程,我的标识PID是".posix_getpid().",我的父进程是:".posix_getppid()."我的子进程是".$pid."\n";
}else{
echo "我是父进程,我的标识PID是".posix_getpid().",我的父进程是:".posix_getppid()."我的子进程是".$pid."\n";
}
// while(1){
// ;
// }
运行:
一般情况下:都是父进程先运行,子进程后运行,如果说父进程先运行,先结束,这个时候这个子进程它就没有父亲了,没有了父亲的进程,我们称之为孤儿进程
孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程。这些孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
参考easyswoole官方的文档:
孤儿进程
示例:
// 让我们来愉快的学习php的多进程
echo '当前进程的pid:'.posix_getpid()."\n"; // 当前进程的标识PID
echo '当前进程的父进程pid:'.posix_getppid()."\n"; // 当前进程父进程的标识PID
$pid = pcntl_fork(); // 官方说当前fork返回的是子进程的标识PID
if($pid == -1){
die("开启进程失败!"); // 开启失败
}elseif ($pid == 0){
sleep(5);
echo "我是子进程,我的标识PID是".posix_getpid().",我的父进程是:".posix_getppid()."我的子进程是".$pid."\n";
while(1){
echo "别走啊!爸爸"."\n";
sleep(1);
}
}else{
// sleep(2);
echo "我是父进程,我的标识PID是".posix_getpid().",我的父进程是:".posix_getppid()."我的子进程是".$pid."\n";
echo "儿子爸爸执行完了我就先跑了"."\n";
}
// while(1){
// ;
// }
当我们去停止输出 "别走啊!爸爸"的时候
原因:
父进程必须先让子进程先结束,如果说父进程先结束,子进程被1号进程接管,变成孤儿进程
如果说子进程先结束,父进程后结束,这种情况一般来说是正常的,因为父进程应该回收子进程产生的数据
子进程结束时还会生成一些数据,比如说状态码等其它信息,并没有完全释放,需要父进程回收
孤儿进程没有任何危害,只是需要注意自己的代码逻辑即可。
如果子进程里面是死进程 这个时候就需要强制杀死这个孤儿进程
# 强制杀死进程
kill -9 <pid>
# 杀掉所有同名进程
killall <pname>