在一般的 Server 程序中都会有一些耗时的任务,比如:发送邮件、聊天服务器发送广播等。如果我们采用同步阻塞的防水去执行这些任务,那么这肯定会非常的慢。

Swoole 的 TaskWorker 进程池可以用来执行一些异步的任务,而且不会影响接下来的任务,很适合处理以上场景。

那么什么是异步任务呢?

可以从下面的图示中来简单了解一下。(来源于网络,侵删)

我们上一个 Swoole 的文章介绍了如何创建一个简单的服务器,并且知道了几个核心的回调函数的使用方法。

要实现上述的异步处理,只需要增加两个事件回调即可:onTask 和 onFinish, 这两个回调函数分别用于执行 Task 任务和处理 Task 任务的返回结果。另外还需要在 set 方法中设置 task 进程数量。

使用示例:


  1. class Server
  2. {
  3. private $serv;
  4. public function __construct() {
  5. $this->serv = new swoole_server("0.0.0.0", 9501);
  6. $this->serv->set(array(
  7. 'worker_num' => 4,
  8. 'daemonize' => false,
  9. 'task_worker_num' => 8
  10. ));
  11. $this->serv->on('Start', array($this, 'onStart'));
  12. $this->serv->on('Connect', array($this, 'onConnect'));
  13. $this->serv->on('Receive', array($this, 'onReceive'));
  14. $this->serv->on('Close', array($this, 'onClose'));
  15. $this->serv->on('Task', array($this, 'onTask'));
  16. $this->serv->on('Finish', array($this, 'onFinish'));
  17. $this->serv->start();
  18. }
  19. public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
  20. echo "Get Message From Client {$fd}:{$data}\n";
  21. // 发送任务到Task进程
  22. $param = array(
  23. 'fd' => $fd
  24. );
  25. $serv->task( json_encode( $param ) );
  26. echo "继续处理之后的逻辑\n";
  27. }
  28. public function onTask($serv, $task_id, $from_id, $data) {
  29. echo "This Task {$task_id} from Worker {$from_id}\n";
  30. echo "Data: {$data}\n";
  31. for($i = 0 ; $i < 5 ; $i ++ ) {
  32. sleep(1);
  33. echo "Task {$task_id} Handle {$i} times...\n";
  34. }
  35. $fd = json_decode( $data , true )['fd'];
  36. $serv->send( $fd , "Data in Task {$task_id}");
  37. return "Task {$task_id}'s result";
  38. }
  39. public function onFinish($serv,$task_id, $data) {
  40. echo "Task {$task_id} finish\n";
  41. echo "Result: {$data}\n";
  42. }
  43. public function onStart( $serv ) {
  44. echo "Server Start\n";
  45. }
  46. public function onConnect( $serv, $fd, $from_id ) {
  47. echo "Client {$fd} connect\n";
  48. }
  49. public function onClose( $serv, $fd, $from_id ) {
  50. echo "Client {$fd} close connection\n";
  51. }
  52. }
  53. $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 三个函数。


  1. class Server
  2. {
  3. private $serv;
  4. public function __construct() {
  5. $this->serv = new swoole_server("0.0.0.0", 9501);
  6. $this->serv->set(array(
  7. 'worker_num' => 4,
  8. 'daemonize' => false,
  9. 'task_worker_num' => 8 // task进程数量 即为维持的MySQL连接的数量
  10. ));
  11. $this->serv->on('Start', array($this, 'onStart'));
  12. $this->serv->on('Connect', array($this, 'onConnect'));
  13. $this->serv->on('Receive', array($this, 'onReceive'));
  14. $this->serv->on('Close', array($this, 'onClose'));
  15. $this->serv->on('Task', array($this, 'onTask'));
  16. $this->serv->on('Finish', array($this, 'onFinish'));
  17. $this->serv->start();
  18. }
  19. public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
  20. echo "收到数据". $data . PHP_EOL;
  21. // 发送任务到Task进程
  22. $param = array(
  23. 'sql' => $data, // 接收客户端发送的 sql
  24. 'fd' => $fd
  25. );
  26. $serv->task( json_encode( $param ) ); // 向 task 投递任务
  27. echo "继续处理之后的逻辑\n";
  28. }
  29. public function onTask($serv, $task_id, $from_id, $data) {
  30. echo "This Task {$task_id} from Worker {$from_id}\n";
  31. echo "recv SQL: {$data['sql']}\n";
  32. static $link = null;
  33. $sql = $data['sql'];
  34. $fd = $data['fd'];
  35. HELL:
  36. if ($link == null) {
  37. $link = @mysqli_connect("127.0.0.1", "root", "root", "test");
  38. }
  39. $result = $link->query($sql);
  40. if (!$result) { //如果查询失败
  41. if(in_array(mysqli_errno($link), [2013, 2006])){
  42. //错误码为2013,或者2006,则重连数据库,重新执行sql
  43. $link = null;
  44. goto HELL;
  45. }
  46. }
  47. if(preg_match("/^select/i", $sql)){//如果是select操作,就返回关联数组
  48. $data = array();
  49. while ($fetchResult = mysqli_fetch_assoc($result) ){
  50. $data['data'][] = $fetchResult;
  51. }
  52. }else{//否则直接返回结果
  53. $data['data'] = $result;
  54. }
  55. $data['status'] = "OK";
  56. $data['fd'] = $fd;
  57. $serv->finish(json_encode($data));
  58. }
  59. public function onFinish($serv, $task_id, $data) {
  60. echo "Task {$task_id} finish\n";
  61. $result = json_decode($result, true);
  62. if ($result['status'] == 'OK') {
  63. $this->serv->send($result['fd'], json_encode($result['data']) . "\n");
  64. } else {
  65. $this->serv->send($result['fd'], $result);
  66. }
  67. }
  68. public function onStart( $serv ) {
  69. echo "Server Start\n";
  70. }
  71. public function onConnect( $serv, $fd, $from_id ) {
  72. echo "Client {$fd} connect\n";
  73. }
  74. public function onClose( $serv, $fd, $from_id ) {
  75. echo "Client {$fd} close connection\n";
  76. }
  77. }
  78. $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. JQ UI dialog

    初始化参数 对于 dialog 来说,首先需要进行初始化,在调用 dialog 函数的时候,如果没有传递参数,或者传递了一个对象,那么就表示在初始化一个对话框. 没有参数,表示按照默认的设置初始化对话 ...

  2. [luogu1772 ZJOI2006] 物流运输 (最短路 线性dp)

    题目描述 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪. ...

  3. 新手学python-Day3-模块

    模块就是引入别人写的,官方写的工具库,就像扳手,钳子,电锯

  4. IntelliJ IDEA 初始化项目时No Java SDK Found

    IntelliJ IDEA 初始化项目时No Java SDK Found 自己在Project SDK后面的New按钮进行JDK的添加:

  5. Android程序之全国天气预报查询(聚合数据开发)

    一.项目演示效果例如以下: 项目源码下载地址: http://pan.baidu.com/s/1pL6o5Mb password:5myq 二.使用 聚合数据SDK: (1)聚合数据官网地址:http ...

  6. CSS3弹性布局内容对齐(justify-content)属性使用具体解释

    内容对齐(justify-content)属性应用在弹性容器上.把弹性项沿着弹性容器的主轴线(main axis)对齐. 该操作发生在弹性长度以及自己主动边距被确定后. 它用来在存在剩余空间时怎样加以 ...

  7. Flutter 1.5 发布,正式成为全平台 UI 框架!

    一. 序 在 Google I/O 2019 上,Dart 团队宣布推出新的 Flutter 稳定版本 1.5,这是 Flutter 迄今为止最大的一次版本发布. 伴随着 Flutter 1.5 的发 ...

  8. Python爬糗百热门20条并邮件分发+wxPython简易GUI+py2app转成可运行文件

    学了一阵子Python,拿来做个什么有意思的东西呢?爬糗百好了.爬到的内容,邮件分发出去. 然后又啃了两天的wxpython,做了个简易的邮件管理界面,能够在这里添加或者删除邮件,而且一键爬虫发送. ...

  9. 2016 ICPC CAMP Recording

    等了好久终于等到今天 马上能和群巨们一起学习了 希望不要暴露我太弱的本质............ 北京不冷,就是风大~~~ 1.24 8点准时起床了,准备下楼吃早饭 (这个宾馆好多美美的空姐对面就是东 ...

  10. jmeter脚本编写之五类常见请求编写

    1.普通post请求 2.普通json请求 3.带query參数的json请求 4.xml请求 5.上传请求 starting (Windows系统 点击 F12 调出开发人员工具,选择Network ...