先了解一下process和event loop
EventLoop
除了异步Server
和Client
库之外,Swoole
扩展还提供了直接操作底层epoll/kqueue
事件循环的接口。可将其他扩展创建的socket
,PHP
代码中stream/socket
扩展创建的socket
等加入到Swoole
的EventLoop
中。
事件优先级
- 通过
Process::signal
设置的信号处理回调函数 - 通过
Event::defer
设置的延迟执行函数 - 通过
Timer::tick
和Timer::after
设置的定时器回调函数 - 通过
Event::cycle
设置的周期回调函数
swoole_event_add
函数用于将一个socket加入到底层的reactor
事件监听中。此函数可以用在Server
或Client
模式下
参数
参数1可以为以下四种类型:
int
,就是文件描述符,包括swoole_client->$sock
、swoole_process->$pipe
或者其他fd
stream
资源,就是stream_socket_client/fsockopen
创建的资源sockets
资源,就是sockets
扩展中socket_create
创建的资源,需要在编译时加入./configure --enable-sockets
object
,swoole_process
或swoole_client
,底层自动转换为管道或客户端连接的socket
参数2
为可读回调函数,参数3
为可写事件回调,可以是字符串函数名、对象+方法、类静态方法或匿名函数,当此socket
可读时回调指定的函数。
参数4
为事件类型的掩码,可选择关闭/开启可读可写事件,如SWOOLE_EVENT_READ
,SWOOLE_EVENT_WRITE
,或者SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE
在 Server 程序中使用时,必须在 Worker 进程启动后使用。在 Server::start 之前不得调用任何异步 IO 接口
在fpm当中一个请求结束了线程就被关掉了,注册的事件就不会再去监听了
event lop实例:
命令符聊天室
主要应用点:
异步读取来自副武器的数据
异步读取来自终端的输入
手动退出聊天室
监听服务器的读和写操作
服务端是不会挺停止的
process
PHP自带的pcntl,存在很多不足,如
- pcntl没有提供进程间通信的功能
- pcntl不支持重定向标准输入和输出
- pcntl只提供了fork这样原始的接口,容易使用错误
- swoole_process提供了比pcntl更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。
swoole_process提供了如下特性:
- swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可
- swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据
- 配合swoole_event模块,创建的PHP子进程可以异步的事件驱动模式
- swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信
curl实例:多进程执行任务和执行一个外部的程序
<?php /** * Created by PhpStorm. * User: baidu * Date: 18/3/17 * Time: 上午12:31 */ echo "process-start-time:".date("Ymd H:i:s"); $workers = []; $urls = [ 'http://baidu.com', 'http://sina.com.cn', 'http://qq.com', 'http://baidu.com?search=singwa', 'http://baidu.com?search=singwa2', 'http://baidu.com?search=imooc', ]; for($i = 0; $i < 6; $i++) { // 子进程 $process = new swoole_process(function(swoole_process $worker) use($i, $urls) { // curl $content = curlData($urls[$i]); //echo $content.PHP_EOL; $worker->write($content.PHP_EOL); }, true); $pid = $process->start(); $workers[$pid] = $process; } foreach($workers as $process) { echo $process->read(); } /** * 模拟请求URL的内容 1s * @param $url * @return string */ function curlData($url) { // curl file_get_contents sleep(1); return $url . "success".PHP_EOL; } echo "process-end-time:".date("Ymd H:i:s");
$process = new swoole_process(function(swoole_process $pro) { // todo // php redis.php $pro->exec("/home/work/study/soft/php/bin/php", [__DIR__.'/../server/http_server.php']); }, false); $pid = $process->start(); echo $pid . PHP_EOL; swoole_process::wait();
process实例:
<?php class BaseProcess{ private $process; public function __construct() { $this->process = new swoole_process([$this,'run'],false,true); $this->process->start(); swoole_event_add($this->process->pipe,function($pipe){ $data = $this->process->read(); echo 'RECV: '.$data.PHP_EOL; }); } public function run($worker){ swoole_timer_tick(1000,function($timer_id){ static $index = 0 ; $index += 1; $this->process->write('hello sunlong'); var_dump($index); if($index == 10){ swoole_timer_clear($timer_id); } }); } } new BaseProcess(); swoole_process::signal(SIGCHLD,function($sig){ while($ret = swoole_process::wait(false)){ echo "PID={$ret['pid']} "; } });
返回结果
[root@localhost php]# php7 process2.php int(1) RECV: hello sunlong int(2) RECV: hello sunlong int(3) RECV: hello sunlong int(4) RECV: hello sunlong int(5) RECV: hello sunlong int(6) RECV: hello sunlong int(7) RECV: hello sunlong int(8) RECV: hello sunlong int(9) RECV: hello sunlong int(10) RECV: hello sunlong PID=2903
上述案例 创建子进程,然后执行定时器,定时器向管道写入数据;swoole_event_add监听管道写事件回调(异步监听管道数据),读取到写的内容并输出。
此时程序还没终止,event loop还在监听管道数据
下面是消息队列作为进程间通信 消息队列同步的 不支持异步
[root@localhost php]# php7 process2.php int(1) RECV: hello sunlong int(2) RECV: hello sunlong int(3) RECV: hello sunlong int(4) RECV: hello sunlong int(5) RECV: hello sunlong int(6) RECV: hello sunlong int(7) RECV: hello sunlong int(8) RECV: hello sunlong int(9) RECV: hello sunlong int(10) RECV: hello sunlong
升华一下 实现简单的进程池 动态扩展进程池 同时处理更多任务
但是推荐使用swoole_server+task做任务池
swoole_process->exec
process在swoole_server中还是有实际运用的,比如执行脚本或者shell命令,linux的tail,top,ps持续的命令,通过管道实时监听,展示在网页上,做成一个外部监控器(process应用)
task执行一个长耗时任务,
两者有重叠但是也有区别