本文实例讲述了php多进程应用场景。分享给大家供大家参考,具体如下:
pcntl介绍
扩展介绍
php多进程模块依赖pcntl扩展,官方手册介绍:http://php.net/manual/zh/book.pcntl.php
Note:
1. 此扩展在 Windows 平台上不可用。
2. 进程控制不能被应用在Web服务器环境,当其被用于Web服务环境时可能会带来意外的结果。因此,不能再PHP Web开发中使用多进程。
安装扩展
# 通过pecl安装pcntl扩展 sudo pecl install pcntl # 增加 extension=pcntl.so sodo vim /etc/php.ini # 检查扩展是否安装成功 php -m | grep pcntl
处理文件
当一个文件包含许多任务(每个任务一行),并且各任务之间不存在执行的先后顺序关系,可以将文件进行分割(分割后的文件数量与进程数一致),然后使用多进程进行处理。
例如,现在有10个邮箱账号存储在文件mailist.txt中,每次发送邮件需要耗时2s,则采用单进程依次发送完这些邮件需要耗时20。
如果采用多进程,例如3个进程进行处理,首先需要将文件按行数拆分成3个小文件,其中两个文件是4条记录,一个文件是2条记录。每个进程处理一个小文件,则不同进程发送完邮件的耗时为8、8、6,总耗时取最大值为8s。
拆分文件
原始文件 maillist.txt
000000@163.com
111111@163.com
222222@163.com
333333@163.com
444444@163.com
555555@163.com
666666@163.com
777777@163.com
888888@163.com
999999@163.com
拆分操作
split -a 1 -l 4 maillist.txt task
拆分后的文件
taska
000000@163.com
111111@163.com
222222@163.com
333333@163.com
taskb
444444@163.com
555555@163.com
666666@163.com
777777@163.com
taskc
888888@163.com
999999@163.com
class WebServer { private $list; public function __construct() { $this->list = []; } public function worker($request){ $pid = pcntl_fork(); if($pid == -1){ return false; } if($pid > 0){ return $pid; } if($pid == 0){ $time = $request[0]; $method = $request[1]; $start = time(); echo getmypid()."\t start ".$method."\tat".$start.PHP_EOL; sleep($time); $end = time(); $cost = $end-$start; echo getmypid()."\t stop \t".$method."\tat:".$end."\tcost:".$cost.PHP_EOL; exit(0); } } public function master($requests){ $start = time(); echo "All request handle stop at ".$start.PHP_EOL; foreach ($requests as $request){ $pid = $this->worker($request); if(!$pid){ echo 'handle fail!'.PHP_EOL; return; } array_push($this->list,$pid); } while(count($this->list)>0){ foreach ($this->list as $k=>$pid){ $res = pcntl_waitpid($pid,$status,WNOHANG); if($res == -1 || $res > 0){ unset($this->list[$k]); } } usleep(100); } $end = time(); $cost = $end - $start; echo "All request handle stop at ".$end."\t cost:".$cost.PHP_EOL; } } $requests = [ [1,'GET index.php'], [2,'GET index.php'], [3,'GET index.php'], [4,'GET index.php'], [5,'GET index.php'], [6,'GET index.php'] ]; $server = new WebServer(); $server->master($requests);
输出结果:
All request handle stop at 1504513048
18945 start GET index.php at1504513048
18944 start GET index.php at1504513048
18946 start GET index.php at1504513048
18947 start GET index.php at1504513048
18948 start GET index.php at1504513048
18949 start GET index.php at1504513048
18944 stop GET index.php at:1504513049 cost:1
18945 stop GET index.php at:1504513050 cost:2
18946 stop GET index.php at:1504513051 cost:3
18947 stop GET index.php at:1504513052 cost:4
18948 stop GET index.php at:1504513053 cost:5
18949 stop GET index.php at:1504513054 cost:6
All request handle stop at 1504513054 cost:6
如果依次处理请求,总耗时为1+2+3+4+5+6=21s。每个请求创建一个进程的处理方式,总耗时是最耗时的请求操作6s。
多进程最好在方法、函数或者文件中单独使用,这样逻辑更加清晰,也便于分析和维护。
附录
邮件操作类:
MailWork.php
<?php /** * Created by PhpStorm. * User: zhezhao * Date: 2017/9/4 * Time: 上午10:05 */ class MailWork { private $error; private $name; public function __construct($name) { $this->name = $name; } public function getLastError(){ return $this->error; } public function checkEnv($argc) { if (substr(php_sapi_name(), 0, 3) !== 'cli') { $this->error ="This Programe can only be run in CLI mode"; return false; } if($argc!=2){ $this->error = 'wrong params'; return false; } return true; } public function getFileName($argv){ $filename = "task".$argv[1]; if(!file_exists($filename)){ $this->error = 'file does not exits'; return false; }else{ return $filename; } } public function sendMail($mailto) { sleep(2); echo $this->name."#mailto:".$mailto.PHP_EOL; } public function text_mail($argc,$argv){ if(!$this->checkEnv($argc)){ return false; } $filename = $this->getFileName($argv); if(!$filename){ return false; } $fp = fopen($filename,'r'); $counter = 0; while(!feof($fp)){ $line = fgets($fp); $mailto = substr($line,0,strlen($line)-1); if(preg_match('/^\w+@\w+\.\w+$/',$mailto)){ $this->sendMail($mailto); $counter++; } } return $counter; } public function redis_mail($mailto){ if(preg_match('/^\w+@\w+\.\w+$/',$mailto)){ $this->sendMail($mailto); } } }
更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP进程与线程操作技巧总结》、《PHP网络编程技巧总结》、《PHP基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。