在一般的 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的更多相关文章

  1. aioysql(异步操作MySQL)-python

    python异步IO初探 探索异步IO执之前,先说说IO的种类 阻塞IO最简单,即读写数据时,需要等待操作完成,才能继续执行.进阶的做法就是用多线程来处理需要IO的部分,缺点是开销会有些大. 非阻塞I ...

  2. 17.swoole学习笔记--异步mysql操作

    <?php //异步mysql操作 $db=new swoole_mysql(); $config=[ 'host'=>'192.168.10.31', 'user'=>'zouke ...

  3. php如何在mysql里批量插入数据

    假如说我有这样一个表,我想往这个表里面插入大量数据 CREATE TABLE IF NOT EXISTS `user_info` ( `id` int(11) NOT NULL AUTO_INCREM ...

  4. PHP 当Swoole 遇上 ThinkPHP5

    本文假设你已经有了 Linux 操作系统的 PHP 环境,强烈推荐使用 Vagrant 来搭建开发环境 安装 Swoole PECL 拓展可以通过 pecl 命令或者通过源码包编译安装,本文采用 pe ...

  5. Swoole跟thinkphp5结合开发WebSocket在线聊天通讯系统

    ThinkPHP使用Swoole需要安装 think-swoole Composer包,前提系统已经安装好了Swoole PECL 拓展* tp5的项目根目录下执行composer命令安装think- ...

  6. 【实战】如何通过html+css+mysql+php来快速的制作动态网页(以制作一个博客网站为列)

    一.开发环境的搭建 (1)apache+php+mysql环境搭建 因为要用apache来做服务器,mysql作为数据库来存储数据,php来写代码以此实现网页与数据库的交互数据,所以需要下载上述软件, ...

  7. swoole,http\server 跨域---记一次php网站跨域访问上机实验

    缘由:为了更好的体验swoole组件优良的协程Mysql客户端,实现更好的并发设计:写了一个小程序. 环境准备: 没有采用任何框架,只是使用了smarty模版,来渲染后端php响应的数据,在一个htm ...

  8. tornado+peewee-async+peewee+mysql(一)

    前言: 需要异步操作MySQL,又要用orm,使用sqlalchemy需要加celery,觉得比较麻烦,选择了peewee-async 开发环境 python3.6.8+peewee-async0.5 ...

  9. Swoole 协程简介

    什么是协程 协程可以简单理解为线程,只不过这个线程是用户态的,不需要操作系统参与,创建.销毁和切换的成本都非常低. 协程不能利用多核 cpu,想利用多核 cpu 需要依赖 Swoole 的多进程模型. ...

随机推荐

  1. 基于selectors模块实现并发的FTP

    import socketimport os,sysBASE_DIR = os.path.dirname(os.path.abspath(__file__)) class selectFtpClien ...

  2. 安装SSH、配置SSH无密码登录 ssh localhost

    集群.单节点模式都需要用到 SSH 登陆(类似于远程登陆,你可以登录某台 Linux 主机,并且在上面运行命令),Ubuntu 默认已安装了 SSH client,此外还需要安装 SSH server ...

  3. axios统一拦截配置

    在vue项目中,和后台进行数据交互使用axios.要想统一处理所有的http请求和响应,就需要使用axios的拦截器.通过配置http response inteceptor 统一拦截后台的接口数据, ...

  4. 递归树处理,配合vue的vueTreeselect组件使用

    在项目中经常会使用到tree,并且需要对递归树进行操作. 在vue项目中,使用vue-treeselect插件(https://vue-treeselect.js.org/) 使用中遇到的问题: 1. ...

  5. Unity 多场景打包

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/50580641 作者:car ...

  6. 《一个民企CEO的职场阳谋》–读书总结(下)

    职场是一个战场,很多人几十年在这里战斗. 职场是一个熔炉,很多人大半生在这里修炼. 如果在办公室里得不到快乐,生活就不会快乐. 如果公司里头感觉不到幸福,人生就不会幸福.(以上四句来自老刘的博客) & ...

  7. Vue-router入门

    1.npm install vue-router --save-dev 安装路由包,在安装脚手架时实际上可以直接安装 2.解读核心文件 router/index.js文件 import Vue fro ...

  8. CSS隐藏overflow默认滚动条同时保留滚动效果

    主要应用于移动端场景,仿移动端滚动效果.对于隐藏滚动条,众所周知overflow:hidden,但是想要的滚动效果也没了. 所以对于移动端webkit内核提供一个伪类选择器: .element::-w ...

  9. 【codeforces 812A】Sagheer and Crossroads

    [题目链接]:http://codeforces.com/contest/812/problem/A [题意] 有一个小箭头指的那个地方; 指的就是人行道路; 然后p[i]指的就是那4个人行道是不是绿 ...

  10. xpee.vbs

    xpee.vbs Win 8安装之后每一次重启桌面都会有一个360浏览器的快捷方式,终于找到原因了, 在Windows/System下面有这么个文件: Set ws = CreateObject(&q ...