一些耗时任务:php
因此咱们就须要一个常驻内存的任务管理工具,为了保证明时性,一方面咱们让它一直执行任务(适当的睡眠,保证cpu不被100%占用),另外一方面咱们实现多进程保证并发的执行任务,固然除此以外也可按状况使用线程、协程实现。linux
实现PHP进程前,需了解常见的php的运行模式:服务器
而php进程则是使用CLI命令行模式运行的并发
PHP中提供了一个扩展pcntl,能够利用操做系统的fork调用来实现多进程。fork调用后执行的代码将是并行的,且只能在linux下运行。socket
$ppid = posix_getpid();// 获取当前进程PID $pid = pcntl_fork(); //建立进程 switch ($pid){ // 建立进程错误 case -1: throw new Exception('fork子进程失败!'); break; // 子进程worker case 0: $cpid = posix_getpid(); cli_set_process_title("我是{$ppid}的子进程,个人进程id是{$cpid}."); sleep(30); exit; // 这里exit掉,避免worker继续执行下面的代码而形成一些问题 break; // 主进程master default: cli_set_process_title("我是父进程,个人进程id是{$ppid}."); pcntl_wait($status); // 挂起父进程,等待并返回子进程状态,防止子进程成为僵尸进程 break; }
在命令行php xxx.php运行后,使用ps aux | grep 进程能够看到:函数
若是没看到,多是中文乱码了,使用ps aux,查看工具
或者使用ps –ajft查看层次显示oop
建立好了进程,那么怎么对子进程进行管理呢?使用信号,对子进程的管理,通常有两种状况:
posix_kill():此函数并不能顾名思义,它经过向子进程发送一个信号来操做子进程,在须要要时能够选择给子进程发送进程终止信号来终止子进程;
pcntl_waitpid():等待或返回fork的子进程状态,若是指定的子进程在此函数调用时已经退出(俗称僵尸进程),此函数将马上返回,并释放子进程的全部系统资源,此进程能够避免子进程变成僵尸进程,形成系统资源浪费;性能
孤儿进程:父进程挂了,子进程被pid=1的init进程接管(wait/waitpid),直到子进程自身生命周期结束被系统回收资源和父进程 采起相关的回收操做
僵尸进程:子进程exit退出,父进程没有经过wait/waitpid获取子进程状态,子进程占用的进程号等描述资源符还存在,产生危害:例如进程号是有限的,没法释放进程号致使将来可能无进程号可用大数据
**父进程中使用:pcntl_wait或者pcntl_waitpid的目的就是防止worker成为僵尸进程
做用:使用pcntl_wait()后,在子进程死掉后,父进程也会被中止**
最后咱们经过下图(1-1)来简单的总结和描述这个多进程实现的过程:
队列:如Redis,推荐
socket:推荐
管道:实现复杂,且管道(pipe),使用文件形式存在,存在硬盘IO性能瓶颈
信号:承载信息量少,很差管理
使用&实现
php deadloop.php &
一个耗时10S的任务,执行2次,总耗时20S,而开2个进程,只需10S,以下:
job.php:
index.php(进程开启脚本):
echo '开始时间:'.date('H:i:s', time())."\n"; $cmds = [ ['./job.php', 0, 50000],//执行脚本,并传参 ['./job.php', 50000, 100000] ]; for ($i = 0; $i < 2; $i++){ $ppid = posix_getpid();// 获取当前进程PID $pid = pcntl_fork(); //建立进程 switch ($pid){ // 建立进程错误 case -1: throw new Exception('fork子进程失败!'); break; // 子进程worker case 0: $cpid = posix_getpid(); cli_set_process_title("我是{$ppid}的子进程,个人进程id是{$cpid}."); // 执行业务脚本 pcntl_exec('/usr/local/php/bin/php', $cmds[$i]); exit; // 这里exit掉,避免worker继续执行下面的代码而形成一些问题 break; } } // 等待子进程结束 while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo '子进程结束时间:'.date('H:i:s', time())."\n"; }
运行php index.php后:
实例达到理想效果。