当前位置: 首页 > Linux

使用swoole_process实现PHP进程池

时间:2023-04-06 19:26:02 Linux

swoole_process主要用于替换PHP的pcntl扩展。我们知道pcntl是用来进行多进程编程的,而pcntl只是提供了像fork一样的原始接口,容易被错误使用,并没有提供进程间通信和标准输入输出的重定向功能。而swoole_process提供了比pcntl更强大的功能和更易用的API,让PHP在多进程编程中更加简单。本文使用swoole_process和EventLoop完成一个php进程池,支持动态创建新进程。EventLoopswoole有一个Reactor线程,可以说是对epoll模型的封装,可以设置read事件和write事件的监听回调函数。下面会用到一个函数:boolswoole_event_add(mixed$sock,mixed$read_callback,mixed$write_callback=null,int$flags=null);参数1为文件描述符,包括swoole_client->$sock、swoole_process->$pipe或其他fd(socket_create创建的资源,stream_socket_client/fsockopen创建的资源)参数2为可读事件回调函数参数3为可写事件回调function多进程编程少不了进程间的通信,swoole进程之间有两种通信方式,一种是消息队列(queue),一种是管道(pipe)。那么本文使用的是pipe方法。下面是定时向进程池下发任务的例子。代码:process=newswoole_process(array($this,'run'),false,2);$this->process->start();swoole_process::等待();}publicfunctionrun(){$this->current_num=$this->min_worker_num;//创建所有工作进程for($i=0;$i<$this->current_num;$i++){$process=newswoole_process(array($this,'task_run'),false,2);$pid=$process->start();$this->process_list[$pid]=$process;$this->process_use[$pid]=0;}foreach($this->process_listas$process){swoole_event_add($process->pipe,function($pipe)use($process){$data=$process->read();var_dump($data.'idle');//接收子进程完成的信息,并重置为idle$this->process_use[$data]=0;});}//每秒定时下发任务给workerpipelineswoole_timer_tick(1000,function($timer_id){static$index=0;$index=$index+1;$flag=true;//是否创建一个新的workerforeach($this->process_useas$pid=>$used){if($used==0){$flag=false;//标记为正在使用$this->process_use[$pid]=1;//在父进程中调用write,子进程可以调用read接收此数据$this->process_list[$pid]->write($index."hello");break;}}if($flag&&$this->current_num<$this->max_worker_num){//没有空闲设置worker,新建worker来处理$process=newswoole_process(array($this,'task_run'),false,2);$pid=$process->start();$this->process_list[$pid]=$process;$this->process_use[$pid]=1;$this->process_list[$pid]->write($index."hello");$this->current_num++;}var_dump('第'.$index.'个任务');if($index==10){foreach($this->process_listas$process){$process->write("exit");}swoole_timer_clear($timer_id);$this->process->exit();}});}/***子进程处理*@param$worker*/publicfunctiontask_run($worker){swoole_event_add($worker->pipe,function($pipe)use($worker){$data=$work呃->阅读();var_dump($worker->pid.':'.$data);if($data=='exit'){$worker->exit();出口;}//耗时模拟Tasksleep(5);//告诉主进程完成//在子进程中调用write,父进程可以调用read接收这个数据$worker->write($worker->pid);});}}新进程池();首先定义几个重要的属性:$process_list:Worker进程数组$process_use:正在使用的进程$min_worker_num:最小进程数$max_worker_num:最大进程数$current_num:当前进程数$process:主进程在instance改造时,创建主进程,运行run方法。在run方法中,首先创建所有worker进程,并设置为idle状态,然后遍历所有worker进程,并将其加入EventLoop,设置可读事件,用于接收子进程idle信号。最后,每秒向工作进程下发任务。进程池的动态扩展就是在这里实现的。如果此时没有空闲进程,并且有新的任务,则需要动态创建一个新的进程,并设置为忙碌状态。由于只模拟十个任务,当第十个任务完成后,在父进程中发送exit,让所有子进程退出。运行效果及示意图:参考链接:https://wiki.swoole.com/wiki/...https://opso.coding.me/2018/0...