PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
在一般的 Server 程序中都会有一些耗时的任务,比如:发送邮件、聊天服务器发送广播等。如果我们采用同步阻塞的防水去执行这些任务,那么这肯定会非常的慢。
Swoole 的 TaskWorker 进程池可以用来执行一些异步的任务,而且不会影响接下来的任务,很适合处理以上场景。
那么什么是异步任务呢?
可以从下面的图示中来简单了解一下。(来源于网络,侵删)
我们上一个 Swoole 的文章介绍了如何创建一个简单的服务器,并且知道了几个核心的回调函数的使用方法。
要实现上述的异步处理,只需要增加两个事件回调即可:onTask 和 onFinish, 这两个回调函数分别用于执行 Task 任务和处理 Task 任务的返回结果。另外还需要在 set 方法中设置 task 进程数量。
使用示例:
class Server
{
private $serv;
public function __construct() {
$this->serv = new swoole_server("0.0.0.0", 9501);
$this->serv->set(array(
'worker_num' => 4,
'daemonize' => false,
'task_worker_num' => 8
));
$this->serv->on('Start', array($this, 'onStart'));
$this->serv->on('Connect', array($this, 'onConnect'));
$this->serv->on('Receive', array($this, 'onReceive'));
$this->serv->on('Close', array($this, 'onClose'));
$this->serv->on('Task', array($this, 'onTask'));
$this->serv->on('Finish', array($this, 'onFinish'));
$this->serv->start();
}
public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
echo "Get Message From Client {$fd}:{$data}\n";
// 发送任务到Task进程
$param = array(
'fd' => $fd
);
$serv->task( json_encode( $param ) );
echo "继续处理之后的逻辑\n";
}
public function onTask($serv, $task_id, $from_id, $data) {
echo "This Task {$task_id} from Worker {$from_id}\n";
echo "Data: {$data}\n";
for($i = 0 ; $i < 5 ; $i ++ ) {
sleep(1);
echo "Task {$task_id} Handle {$i} times...\n";
}
$fd = json_decode( $data , true )['fd'];
$serv->send( $fd , "Data in Task {$task_id}");
return "Task {$task_id}'s result";
}
public function onFinish($serv,$task_id, $data) {
echo "Task {$task_id} finish\n";
echo "Result: {$data}\n";
}
public function onStart( $serv ) {
echo "Server Start\n";
}
public function onConnect( $serv, $fd, $from_id ) {
echo "Client {$fd} connect\n";
}
public function onClose( $serv, $fd, $from_id ) {
echo "Client {$fd} close connection\n";
}
}
$server = new Server();
通过上述示例可以看到,发起一个异步任务只需要调用 swoole_server 的 task 方法就可以。发送之后会触发 onTask 回调,可以通过 $task_id 和 $from_id 处理不同进程的不同任务。最后可以通过 return 一个字符串来将执行结果返回给 Worker 进程,Worker 进程通过 onFinish 回调来处理结果。
那么基于上述代码就可以实现异步操作 mysql。异步操作 mysql 较适合以下场景:
- 并发的读写操作
- 没有时序上的严格关系
- 不影响主线程逻辑
好处:
- 提高并发
- 降低 IO 消耗
数据库的压力主要在于 mysql 维持的连接数,如果存在 1000 个并发,那么 mysql 就需要建立对应数量的连接。而采用长连接的方式,mysql 的连接一直维持在进程中,减少了创建连接的损耗。可以通过 swoole 开启多个 task 进程,每一个进程内维持一个mysql 长连接,那么这样子也可以引申出来 mysql 连接池技术。还需要注意的是,mysql 服务器如果检测到长时间没有没有查询,则会断开连接回收资源,所以要有断线重连的机制。
以下是一个简单的异步操作 mysql 的示例:
还是以上的代码,我们只需要修改 onReceive、onTask、onFinish 三个函数。
class Server
{
private $serv;
public function __construct() {
$this->serv = new swoole_server("0.0.0.0", 9501);
$this->serv->set(array(
'worker_num' => 4,
'daemonize' => false,
'task_worker_num' => 8 // task进程数量 即为维持的MySQL连接的数量
));
$this->serv->on('Start', array($this, 'onStart'));
$this->serv->on('Connect', array($this, 'onConnect'));
$this->serv->on('Receive', array($this, 'onReceive'));
$this->serv->on('Close', array($this, 'onClose'));
$this->serv->on('Task', array($this, 'onTask'));
$this->serv->on('Finish', array($this, 'onFinish'));
$this->serv->start();
}
public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
echo "收到数据". $data . PHP_EOL;
// 发送任务到Task进程
$param = array(
'sql' => $data, // 接收客户端发送的 sql
'fd' => $fd
);
$serv->task( json_encode( $param ) ); // 向 task 投递任务
echo "继续处理之后的逻辑\n";
}
public function onTask($serv, $task_id, $from_id, $data) {
echo "This Task {$task_id} from Worker {$from_id}\n";
echo "recv SQL: {$data['sql']}\n";
static $link = null;
$sql = $data['sql'];
$fd = $data['fd'];
HELL:
if ($link == null) {
$link = @mysqli_connect("127.0.0.1", "root", "root", "test");
}
$result = $link->query($sql);
if (!$result) { //如果查询失败
if(in_array(mysqli_errno($link), [2013, 2006])){
//错误码为2013,或者2006,则重连数据库,重新执行sql
$link = null;
goto HELL;
}
}
if(preg_match("/^select/i", $sql)){//如果是select操作,就返回关联数组
$data = array();
while ($fetchResult = mysqli_fetch_assoc($result) ){
$data['data'][] = $fetchResult;
}
}else{//否则直接返回结果
$data['data'] = $result;
}
$data['status'] = "OK";
$data['fd'] = $fd;
$serv->finish(json_encode($data));
}
public function onFinish($serv, $task_id, $data) {
echo "Task {$task_id} finish\n";
$result = json_decode($result, true);
if ($result['status'] == 'OK') {
$this->serv->send($result['fd'], json_encode($result['data']) . "\n");
} else {
$this->serv->send($result['fd'], $result);
}
}
public function onStart( $serv ) {
echo "Server Start\n";
}
public function onConnect( $serv, $fd, $from_id ) {
echo "Client {$fd} connect\n";
}
public function onClose( $serv, $fd, $from_id ) {
echo "Client {$fd} close connection\n";
}
}
$server = new Server();
以上代码在 onReceive 时直接接收一条 sql,之后直接发送到 Task 任务中。这个时候下一步的流程紧接着输出,这里也就体现出了异步。然后 onTask 和 onFinish 分别用来向数据库发送 sql,处理 task 执行结果。
参考链接:
https://wiki.swoole.com
http://rango.swoole.com/archi...
原文地址:https://segmentfault.com/a/1190000016706048
PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql的更多相关文章
- aioysql(异步操作MySQL)-python
python异步IO初探 探索异步IO执之前,先说说IO的种类 阻塞IO最简单,即读写数据时,需要等待操作完成,才能继续执行.进阶的做法就是用多线程来处理需要IO的部分,缺点是开销会有些大. 非阻塞I ...
- 17.swoole学习笔记--异步mysql操作
<?php //异步mysql操作 $db=new swoole_mysql(); $config=[ 'host'=>'192.168.10.31', 'user'=>'zouke ...
- php如何在mysql里批量插入数据
假如说我有这样一个表,我想往这个表里面插入大量数据 CREATE TABLE IF NOT EXISTS `user_info` ( `id` int(11) NOT NULL AUTO_INCREM ...
- PHP 当Swoole 遇上 ThinkPHP5
本文假设你已经有了 Linux 操作系统的 PHP 环境,强烈推荐使用 Vagrant 来搭建开发环境 安装 Swoole PECL 拓展可以通过 pecl 命令或者通过源码包编译安装,本文采用 pe ...
- Swoole跟thinkphp5结合开发WebSocket在线聊天通讯系统
ThinkPHP使用Swoole需要安装 think-swoole Composer包,前提系统已经安装好了Swoole PECL 拓展* tp5的项目根目录下执行composer命令安装think- ...
- 【实战】如何通过html+css+mysql+php来快速的制作动态网页(以制作一个博客网站为列)
一.开发环境的搭建 (1)apache+php+mysql环境搭建 因为要用apache来做服务器,mysql作为数据库来存储数据,php来写代码以此实现网页与数据库的交互数据,所以需要下载上述软件, ...
- swoole,http\server 跨域---记一次php网站跨域访问上机实验
缘由:为了更好的体验swoole组件优良的协程Mysql客户端,实现更好的并发设计:写了一个小程序. 环境准备: 没有采用任何框架,只是使用了smarty模版,来渲染后端php响应的数据,在一个htm ...
- tornado+peewee-async+peewee+mysql(一)
前言: 需要异步操作MySQL,又要用orm,使用sqlalchemy需要加celery,觉得比较麻烦,选择了peewee-async 开发环境 python3.6.8+peewee-async0.5 ...
- Swoole 协程简介
什么是协程 协程可以简单理解为线程,只不过这个线程是用户态的,不需要操作系统参与,创建.销毁和切换的成本都非常低. 协程不能利用多核 cpu,想利用多核 cpu 需要依赖 Swoole 的多进程模型. ...
随机推荐
- baidu练习/html/css
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Redis:基础知识及其常用数据类型和关键字
Redis: Redis是什么: REmote DIctionary Server(远程字典服务器) 是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(Key-Value)分布式内存数 ...
- JS 一个简单的隔行变色函数
//输入要隔行变色的标签名 function setbgColor(tr){ var tr = document.getElementsByTagName("tr"); for(v ...
- C#-GC基础(待补充)
Finalize方法与Dispose方法区别 1. Finalize只释放非托管资源: 2. Dispose释放托管和非托管资源: // D 是神的天敌3. 重复调用Finalize和Dispose是 ...
- HDU——T 2119 Matrix
http://acm.hdu.edu.cn/showproblem.php?pid=2119 Time Limit: 5000/1000 MS (Java/Others) Memory Limi ...
- OpenCV特征点检測------Surf(特征点篇)
Surf(Speed Up Robust Feature) Surf算法的原理 ...
- LeetCode OJ 215. Kth Largest Element in an Array 堆排序求解
题目链接:https://leetcode.com/problems/kth-largest-element-in-an-array/ 215. Kth Largest Element in an A ...
- 如何让Java写的程序,脱离Eclipse在别人的电脑上运行?
Java程序运行,离不开JRE. 将JRE文件夹拷贝出来, 将编写程序的bin文件夹拷贝出来, 再编写一个bat文件. start jre\bin\javaw.exe -cp .\bin\ -Djav ...
- mysql裸文件备份XtraBackup (innobackupex)
结构如下: 热备分为逻辑备份和裸文件备份. 裸文件备份比逻辑备份在速度上更快一些,因为它在底层复制数据文件.世界上唯一一款开源的,能够对INNODB和XtrDB数据库进行热备的开源工具. 他的优点是备 ...
- Ubuntu16.04+OpenCV3.2.0+Opencv_Contrib3.2.0安装
为了学习slam,在ubuntu16.04系统上安装opencv3.2.0以及对应的opencv_contrib3.2.0 安装过程 下载 Github上下载有的时候比较慢,我这里分享了OpenCV3 ...