//保证子进程上限 if($this->_maxFork >0 && $this->_children > $this->_maxFork) { Yii::log("_children > ".$this->_maxFork,CLogger::LEVEL_WARNING,__METHOD__); $this->handler(SIGCHLD); // usleep(200); continue; } /** * 监控信号 * @param object socket $clientt * @return boolean */ public function handler($signo) { Yii::log("handler {$signo} ",CLogger::LEVEL_INFO, __METHOD__); switch(intval($signo)) { case SIGCLD: case SIGCHLD: Yii::log("SIGCHLD sub proccess ",CLogger::LEVEL_TRACE, __METHOD__); //正常退出 //declare = 1, that means one signal may be correspond multi-process die while( ($pid = pcntl_wait($status, WNOHANG|WUNTRACED)) > 0 ) { if (FALSE === pcntl_wifexited($status)) { Yii::log("sub proccess {$pid} exited unormally with code {$status}",CLogger::LEVEL_WARNING, __METHOD__); } else { Yii::log("sub proccess {$pid} exited normally",CLogger::LEVEL_INFO, __METHOD__); } $this->_children--; } break; case SIGINT: case SIGQUIT: case SIGHUP: //异常退出 $this->_cleanup(); exit(0); break; default: break; } }
因为是进程,可以理解成主进程的一个拷贝,执行是从调用 pcntl_fork() 后各主、子进程后自往后运行,避免子进程层层嵌套,一般子进程执行完后是用exit(0)来退出。 子进程如果执行过程中崩溃不会影响到主进程,也不能和主进程共享变量。
pcntl_signal 注册信号后会和 stream_select 有冲突PHP Error[2]: stream_select(): unable to select [4]: 被中断的系统调用 (max_fd=10)目前没找到解决方法,未采用 pcntl_signal 进行监控。
子进程通过exit退出后,会变成僵尸进程,需要通过 pcntl_wait 来进行回收。centos 测试中发现最大的进程上限是3.2万,通过设置子进程总数,大于设定值再调用 pcntl_wait 来进行回收
多进程情况下,会出现对同个socket句柄,有多个进程同时在读的问题。解决方法是读操作在主进程里,读出所有数据后,抛给子进程进行执行。
filesize 函数在多进程情况下会出现取不到或取到的文件大小一直不变问题这里采用直接调用 linux下的系统函数解决。
压力测试后1000的并发可达到350每秒的请求。应该还可优化。