PHP本身不支持多线程,多进程支持的也不是特别好,网上找到一份多进程代码(http://jasonyu.cn/html/2010/294.html),写了一个测试程序简单测了一下,可以运行,但是离上线还差得很远。
<?php /** * Project: Signfork: php多线程库 * File: Signfork.class.php */ class Signfork{ /** * 设置子进程通信文件所在目录 * @var string */ private $tmp_path='/tmp/'; /** * Signfork引擎主启动方法 * 1、判断$arg类型,类型为数组时将值传递给每个子进程;类型为数值型时,代表要创建的进程数. * @param object $obj 执行对象 * @param string|array $arg 用于对象中的__fork方法所执行的参数 * 如:$arg,自动分解为:$obj->__fork($arg[0])、$obj->__fork($arg[1])… * @return array 返回 array(子进程序列=>子进程执行结果); */ public function run($obj,$arg=1){ if(!method_exists($obj,'__fork')){ exit('Method "__fork" not found!'); } if(is_array($arg)){ $i=0; foreach($arg as $key=>$val){ $spawns[$i]=$key; $i++; $this->spawn($obj,$key,$val); } $spawns['total']=$i; }elseif($spawns=intval($arg)){ for($i = 0; $i < $spawns; $i++){ $this->spawn($obj,$i); } }else{ exit('Bad argument!'); } if($i>1000) exit('Too many spawns!'); return $this->request($spawns); } /** * Signfork主进程控制方法 * 1、$tmpfile 判断子进程文件是否存在,存在则子进程执行完毕,并读取内容 * 2、$data收集子进程运行结果及数据,并用于最终返回 * 3、删除子进程文件 * 4、轮询一次0.03秒,直到所有子进程执行完毕,清理子进程资源 * @param string|array $arg 用于对应每个子进程的ID * @return array 返回 array([子进程序列]=>[子进程执行结果]); */ private function request($spawns){ $data=array(); $i=is_array($spawns)?$spawns['total']:$spawns; for($ids = 0; $ids<$i; $ids++){ while(!($cid=pcntl_waitpid(-1, $status, WNOHANG)))usleep(30000); $tmpfile=$this->tmp_path.'sfpid_'.$cid; $data[$spawns['total']?$spawns[$ids]:$ids]=file_get_contents($tmpfile); unlink($tmpfile); } return $data; } /** * Signfork子进程执行方法 * 1、pcntl_fork 生成子进程 * 2、file_put_contents 将'$obj->__fork($val)'的执行结果存入特定序列命名的文本 * 3、posix_kill杀死当前进程 * @param object $obj 待执行的对象 * @param object $i 子进程的序列ID,以便于返回对应每个子进程数据 * @param object $param 用于输入对象$obj方法'__fork'执行参数 */ private function spawn($obj,$i,$param=null){ if(pcntl_fork()===0){ $cid=getmypid(); file_put_contents($this->tmp_path.'sfpid_'.$cid,$obj->__fork($param)); posix_kill($cid, SIGTERM); exit; } } } ?>
测试程序如下:
<?php require_once(dirname(__FILE__) . '/Signfork.class.php'); class ExecObj{ public function __fork($param){ return getmypid(); } } echo getmypid()."\n"; $signfork = new Signfork(); $result = $signfork->run(new ExecObj(),5); foreach ($result as $key=>$val) { echo $key." ".$val."\n"; } ?>