6.1. 创建一个子进程并设置进程名称为worker-process 9
概念介绍
Swoole设计的目的就是为了使PHP得到更好的性能,同时也拓展了PHP的应用场景如:
互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域
Swoole在PHP里的角色:就是PHP的一个扩展,类似mbstring扩展一样,使用之前需要先开启这个扩展
注意:swoole暂时还不支持Windows系统
编译安装Swoole扩展
在Linux系统上安装使用源码进行编译安装
环境准备:
1、 安装PHP
2、 安装编译swoole源代码的软件:autoconf(生成配置文件)、gcc(将C语言编译成可执行文件)、make(编译器)
安装autoconf、gcc、make等软件方式:
yum: yum install -y autoconf gcc make
apt-get: apt-get install autoconf gcc make
下载Swoole扩展源码
Github:https://github.com/swoole/swoole-src/releases
(比较新,可能有些版本不稳定)
pecl.php.net:http://pecl.php.net/package/swoole
使用swoole 1.9.6版本:http://pecl.php.net/get/swoole-1.9.6.tgz
->wget http://pecl.php.net/get/swoole-1.9.6.tgz
解压源码压缩包
->tar xf swoole-1.9.6.tgz
编译Swoole
->phpize
->./configure
如果提示没有php-config文件那么使用如下办法解决
后面的安装路径是自己的PHP安装路径
->make
注意:如果想加快make 编译速度,那么可以使用 -jCPU核心数
例如make -j2 后面的2指的就是使用两个CPU核心同时运算。
->make install
在php.ini开启swoole扩展
编译好的swoole.so文件
/usr/local/php/lib/php/extensions/no-debug-non-zts-20160303/ 一般是默认位置
查看扩展是否开启成功
->php -m|grep swoole
到此swoole扩展编译安装完成。
Swoole的线程和进程的模型
参考网址:http://rango.swoole.com/ 开发者博客
Swoole会开启 “多个”进程
Worker进程:代码业务逻辑通常是在Worker进程中处理的
Worker进程被Manager进程所管理
Master进程负责管理一系列的线程这些线程比较偏底层
Swoole的执行过程
Swoole支持的常用事件列表
swoole执行流程中几个需要注意的点
1. 在swoole服务器启动后,会创建三个进程
* Manager
* Worker
* Task
这个Manager进程是Worker进程的守护进程,在这个Worker进程意外结束后,这个Manager进程会重新启动Workder进程,Manager进程只有一个,而这个Worker可以有多个。
Worker进程通过给这个Task进程发送任务,可以把一些计算量大的任务转移到Task进程,这样我们的Worker进程就可以高速处理客户端的请求,提高并发量。
Swoole的HTTP服务器
swoole的http请求对象是:swoole_http_request这个类的对象
swoole的http响应对象是:swoole_http_response这个类的对象
效果:
swoole程序编写的流程
1. 创建swoole服务器对象
2. 为这个对象设置回调函数
3. 处理业务逻辑
4.启动swoole服务器
Swoole的WebSocket服务器
websocket服务器的事件
通过调用这个类swoole_websocket_server的push可以给websocket客户端发送消息
通过调用这个类swoole_websocket_frame的data属性可以得到websocket客户端发送给websocket服务器的消息
效果:
处理计算器的业务逻辑:
#创建一个websocket服务器
$serv=new swoole_websocket_server(“0.0.0.0”,8000);
$serv->on(“message”,function(swoole_websocket_server $server, $frame){
// var_dump($server,$frame);
#获取客户端发送的数据信息
$data=json_decode($frame->data,true);
// var_dump($data);
switch ($data[‘operator’]){
case “+”:
$resust=$data[‘firstNumber’]+$data[‘secondNumber’];
break;
case “-“:
$resust=$data[‘firstNumber’]-$data[‘secondNumber’];
break;
case “*”:
$resust=$data[‘firstNumber’]*$data[‘secondNumber’];
break;
case “/”:
$resust=$data[‘firstNumber’]/$data[‘secondNumber’];
break;
}
//从服务器端将运算的结果推送给浏览器客户端。
$server->push($frame->fd,$resust);//$frame->fd就是客户端的唯一标识
});
#启动websocket_server服务器
$serv->start();
最终效果:
MySQL连接池
场景:每秒同时有1000个并发,但是这个mysql同时只能处理400个连接,mysql会宕机。
解决方案:连接池:连接池建立了200个和mysql的连接,这1000个并发就有顺序的共享这连接池中的200个连接。
连接池能够带来额外的性能提升,因为mysql建立连接的过程消耗较大,使用连接池只需连接一次mysql。
连接池
1. “永不断开”,要求我们的程序是一个常驻内存的程序
首先swoole满足上面的要求那么就用swoole编写mysql的连接池。
分析思路:
1、 使用单例模式固定连接池
2、 确定连接池的连接数(总数),以及可用的连接数
3、 使用数组保存连接池中的连接对象
4、 在构造函数中,根据连接数,逐个产生连接对象(MySQL资源连接),并存入数组中
5、 封装一个查询的方法:
1) 首先要判断的是连接数是否已经分配完毕,如果分配完毕,抛出异常
2) 每次查询之前从连接池(数组)中取出一个连接,对应的可用连接数要进行减1操作
3) 查询完成之后,将之前取出的连接放入连接池(数组中),对应的可用连接数要进行加1操作
6、 创建一个http服务器
7、 在request事件内部进行数据查询操作
#编写一个类实现连接池的效果。
class MysqlConnectionsPool{
private static $instance;//该属性用来保存单例对象
private $connections=[];//用来存放生成的mysql连接(池子)
private $conncetionNumber=20;//批量生成20个mysql连接。
private $enableNumber=20;//可用连接数
//编写一个单例
public static function getInstance(){
//判断当前静态属性self::instance是否为空
if(is_null(self::$instance)){
//这里如果为空,那么就需要进行实例化
self::$instance=new self();
}
return self::$instance;
}
private function __clone(){}
private function __construct()
{
//在该构造方法中实现连接池中连接的批量生成。
for($i=0;$i<$this->conncetionNumber;$i++){
//每循环一次生成一个mysql连接
//使用pdo连实现
$dsn=”mysql:host=127.0.0.1;dbname=swoole”;
//生成mysql连接并存入数组中
$this->connections[]=new PDO($dsn,”swoole”,”123456″);
}
var_dump($this->connections);
}
//封装一个查询方法,实现从连接池中取出连接查询数据,查询结束之后要将连接还回连接池
public function query($sql){
if($this->enableNumber==0){
//如果可用连接数为0,那么就说明连接池中的连接被分配完毕
//那么抛出一个异常
throw new Exception(“MySql连接池中的连接已经分配完毕”);
}
#执行到这里则说明连接池中还有连接可用
//那么就从连接池中取出一个连接用来查询数据。
$pdo=array_pop($this->connections);
//可用连接数要对应减一
$this->enableNumber–;
//使用取出的连接进行数据查询
$rows=$pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
#把使用后的mysql连接放入连接池中
array_push($this->connections,$pdo);
#更改可用连接数
$this->enableNumber++;
//返回查询到的数据信息
return $rows;
}
}
MysqlConnectionsPool::getInstance();
#创建一个swoole的http服务器
$serv=new swoole_http_server(“0.0.0.0”,8000);
#绑定事件,目标:当浏览器连接http 服务器时,给浏览器发送一条消息
$serv->on(“request”,function($request,$response){
// var_dump($request,$response);
$stop=false;
while(!$stop){//初始状态下是一个死循环
try{
$sql=”select * from student”;
//调用query方法实现查询效果。
$rows=MysqlConnectionsPool::getInstance()->query($sql);
var_dump($rows);
$stop=true;//查询完成之后修改死循环的状态
}catch(Exception $e){
//如果捕捉到异常,那么就说明连接池中的可用连接已经分配完毕,那么暂停0.1秒再去连接池中取连接
usleep(100000);//暂停0.1秒
}
}
$response->end(“hello swoole”);
});
#启动swoole_http_server服务器
$serv->start();
最终效果:
在mysql中查看当前有多少个连接
->show processlist
使用Swoole管理进程
PHP有一个pcntl的扩展用来管理进程,但是这个扩展比较底层,不好用。
多进程一般用来解决大计算量的问题。
场景:修改当前进程的名字
常规情况下,一个文件在执行,那么必然会有一个对应的进程
解决办法:使用swoole_set_process_name函数修改进程名称
更改效果:
创建一个子进程并设置进程名称为worker-process
等待子进程退出:swoole_process:wait()效果就是只有所有子进程全部退出了,这个主进程才退出。
Swoole常用配置选项
调整worker进程数量
worker进程的数量越多,能同时处理的并发量更高。
默认情况下:创建一个http服务器那么就会产生多个进程
查看生成的进程数量
修改进程数量的代码:
修改task进程数量
实现任务投递功能
#创建一个http服务器
$serv=new swoole_http_server(“0.0.0.0”,8000);
$serv->set(array(
‘worker_num’=>5,//指定worker进程数量为20个
‘task_worker_num’=>3
));
$serv->on(“connect”,function($server, $fd, $from_id){
//当有新的连接进来是,那么就可以进行任务投递
$server->task(“worker进程投递了任务”);//①投递任务
});
$serv->on(“request”,function($requset,$response){
$response->end(“hello swoole”);
});
$serv->on(“Task”,function($serv, $task_id, $from_id, $data){
//这里负责处理任务数据
var_dump($task_id, $from_id,$data);//这个$data就是接受的任务数据信息
//任务处理完成之后②处理任务投递
return “任务进程处理完毕”;
});
$serv->on(“finish”,function( $serv, $task_id, $data){
//处理完成之后向主进程返回数据信息
var_dump($task_id,$data);//③向worker进程返回处理结果
});
#启动服务器
$serv->start();
Swoole毫秒级定时器
场景一:将一段代码延时执行
swoole_timer_after(要执行的函数,延时的毫秒)
执行效果:
场景二:每隔3秒输出123
效果:
异步文件读取
先看同步执行的案例:
代码:
效果:
异步实现文件读取
效果: