Channel通道,类似于go语言的chan,支持多生产者协程和多消费者协程,Swoole底层自动实现了协程的切换和调度

Channel实现原理

通道与PHP的Array类似,仅占用内存,没有其他额外的资源申请,所有操作均为内存操作,无IO消耗

底层使用PHP引用计数实现,无内存拷贝。即使是传递巨大字符串或数组也不会产生额外性能消耗

方法

Channel->push :当队列中有其他协程正在等待pop数据时,自动按顺序唤醒一个消费者协程。当队列已满时自动yield让出控制器,等待其他协程消费数据

Channel->pop:当队列为空时自动yield,等待其他协程生产数据。消费数据后,队列可写入新的数据,自动按顺序唤醒一个生产者协程

连接池

使用Coroutine\Channel来实现MySQL连接池可以使用defer特性来实现资源的回收,同时可以被协程调度,而且使用channel->pop方法的时候,可以设置超时,减少一系列的心智负担

代码实现

namespace SwExample;

class MysqlPool

{

private static $instance;

private $pool; //连接池容器,一个channel

private $config;

/**

* @param null $config

* @return MysqlPool

* @desc 获取连接池实例

*/

public static function getInstance($config = null)

{

if (empty(self::$instance)) {

if (empty($config)) {

throw new \RuntimeException("mysql config empty");

}

self::$instance = new static($config);

}

return self::$instance;

}

/**

* MysqlPool constructor.

*

* @param $config

* @desc 初始化,自动创建实例,需要放在workerstart中执行

*/

public function __construct($config)

{

if (empty($this->pool)) {

$this->config = $config;

$this->pool = new chan($config['pool_size']);

for ($i = 0; $i < $config['pool_size']; $i++) {

$mysql = new MySQL();

$res = $mysql->connect($config);

if ($res == false) {

//连接失败,抛异常

throw new \RuntimeException("failed to connect mysql server.");

} else {

//mysql连接存入channel

$this->put($mysql);

}

}

}

}

/**

* @param $mysql

* @desc 放入一个mysql连接入池

*/

public function put($mysql)

{

$this->pool->push($mysql);

}

/**

* @return mixed

* @desc 获取一个连接,当超时,返回一个异常

*/

public function get()

{

$mysql = $this->pool->pop($this->config['pool_get_timeout']);

if (false === $mysql) {

throw new \RuntimeException("get mysql timeout, all mysql connection is used");

}

return $mysql;

}

/**

* @return mixed

* @desc 获取当时连接池可用对象

*/

public function getLength()

{

return $this->pool->length();

}

}

使用

require '../vendor/autoload.php';

use SwExample\MysqlPool;

$config = [

'host' => '127.0.0.1', //数据库ip

'port' => 3306, //数据库端口

'user' => 'root', //数据库用户名

'password' => 'root', //数据库密码

'database' => 'wordpress', //默认数据库名

'timeout' => 0.5, //数据库连接超时时间

'charset' => 'utf8mb4', //默认字符集

'strict_type' => true, //ture,会自动表数字转为int类型

'pool_size' => '3', //连接池大小

'pool_get_timeout' => 0.5, //当在此时间内未获得到一个连接,会立即返回。(表示所有的连接都已在使用中)

];

//创建http server

$http = new Swoole\Http\Server("0.0.0.0", 9501);

$http->set([

//"daemonize" => true, // 常驻进程模式运行

"worker_num" => 1,

"log_level" => SWOOLE_LOG_ERROR,

]);

$http->on('WorkerStart', function ($serv, $worker_id) use ($config) {

//worker启动时,每个进程都初始化连接池,在onRequest中可以直接使用

try {

MysqlPool::getInstance($config);

} catch (\Exception $e) {

//初始化异常,关闭服务

echo $e->getMessage() . PHP_EOL;

$serv->shutdown();

} catch (\Throwable $throwable) {

//初始化异常,关闭服务

echo $throwable->getMessage() . PHP_EOL;

$serv->shutdown();

}

});

$http->on('request', function ($request, $response) {

//浏览器会自动发起这个请求 避免占用请求

if ($request->server['path_info'] == '/favicon.ico') {

$response->end('');

return;

}

//获取数据库

if ($request->server['path_info'] == '/list') {

go(function () use ($request, $response) {

//从池子中获取一个实例

try {

$pool = MysqlPool::getInstance();

$mysql = $pool->get();

defer(function () use ($mysql) {

//利用defer特性,可以达到协程执行完成,归还$mysql到连接池

//好处是 可能因为业务代码很长,导致乱用或者忘记把资源归还

MysqlPool::getInstance()->put($mysql);

echo "当前可用连接数:" . MysqlPool::getInstance()->getLength() . PHP_EOL;

});

$result = $mysql->query("select * from wp_users");

$response->end(json_encode($result));

} catch (\Exception $e) {

$response->end($e->getMessage());

}

});

return;

}

echo "get request:".date('Y-m-d H:i:s').PHP_EOL;

if ($request->server['path_info'] == '/timeout') {

go(function () use ($request, $response) {

//从池子中获取一个实例

try {

$pool = MysqlPool::getInstance();

$mysql = $pool->get();

defer(function () use ($mysql) {

//协程执行完成,归还$mysql到连接池

MysqlPool::getInstance()->put($mysql);

echo "当前可用连接数:" . MysqlPool::getInstance()->getLength() . PHP_EOL;

});

$result = $mysql->query("select * from wp_users");

\Swoole\Coroutine::sleep(10); //sleep 10秒,模拟耗时操作

$response->end(date('Y-m-d H:i:s').PHP_EOL.json_encode($result));

} catch (\Exception $e) {

$response->end($e->getMessage());

}

});

return;

}

});

$http->start();

访问http://127.0.0.1:9501/list可以看到正常的结果输出

访问http://127.0.0.1:9501/timeout演示连接池取和存的过程

模拟timeout, 需要浏览器打开4个tab页面,都请求http://127.0.0.1:9501/timeout,前三个应该是等10秒出结果,第四个500ms后出超时结果

如果是chrome浏览器,会对完全一样的url做并发请求限制需要加一个随机数,例如http://127.0.0.1:9501/timeout?n=0、http://127.0.0.1:9501/timeout?n=1

mysql多个字符串连接池_使用Coroutine\Channel实现一个简单的MySQL连接池相关推荐

  1. mysql建立数据浏览器_一个简单的MySQL数据浏览器

    一个简单的MySQL数据浏览器 2021-01-21 16:17:28679 这个程序可以用来浏览MySQL中的数据,您可以稍做修改就可以做出很不错的MySQL浏览器. */ /* ?cmd=db ? ...

  2. mysql浏览器_一个简单的MySQL数据浏览器

    一个简单的MySQL数据浏览器 更新时间:2006年10月09日 00:00:00   作者: 这个程序可以用来浏览MySQL中的数据,您可以稍做修改就可以做出很不错的MySQL浏览器. */ /* ...

  3. mysql建立数据浏览器_一个简单的MySQL数据浏览器_php

    这个程序可以用来浏览mysql中的数据,您可以稍做修改就可以做出很不错的MySQL浏览器. */ /* ?cmd=db ?cmd=table&db={} http://www.gaodaima ...

  4. 一个简单的反向连接服务程序

    一个简单的反向连接服务程序 功能简介: 运行后自删除,写注册表Run下,同时自拷贝到系统目录下,注册为系统服务SvrDemo,修改文件时间同Cmd.exe,每隔俩秒钟连接一次本地(127.0.0.1) ...

  5. easyswoole数据库连接池_如何在 Swoole 中优雅的实现 MySQL 连接池

    如何在 Swoole 中优雅的实现 MySQL 连接池 一.为什么需要连接池 ? 数据库连接池指的是程序和数据库之间保持一定数量的连接不断开, 并且各个请求的连接可以相互复用, 减少重复连接数据库带来 ...

  6. jsp获取连接池的实时连接数_PHP进阶教程-实现一个简单的MySQL连接池

    ​什么是连接池? 顾名思义,连接池就是一堆预先创建好的连接,跟容器会有点像.连接池主要是在某种需要网络连接的服务,提前把连接建立好存起来,然后存放在一个池子里面,需要用到的时候取出来用,用完之后再还回 ...

  7. mysql 消息队列_一个简单的 MySQL 批量事务消息队列

    基于 MySQL 的批量事务消息队列 消息队列本质上是一个存储介质,通常是链表结构,不同的进程或线程可以向消息队列中写入或读取消息.消息队列的使用场景有很多,比如异步处理任务.应用解耦.流量削锋等等. ...

  8. python 常量池_聊一聊让我蒙蔽一晚上的各种常量池

    在写之前我们先来看几个问题,假如你对这些问题已经很懂了的话,那大可不用看这篇文章,如果不大懂的话,那么可以看看我的想法. 问题1: public static void main(String[] a ...

  9. linux mysql 怎么启动客服端_脚本之家教你linux如何启动mysql服务教程图解 linux启动mysql服务命令是什么...

    mysql数据库是一种开放源代码的关系型数据库管理系统,有很多朋友都在使用.一些在linux系统上安装了mysql数据库的朋友,却不知道该如何对mysql数据库进行配置.那么linux该如何启动mys ...

最新文章

  1. Ubuntu 18 snap 占用 100%,卸载 snap
  2. MIT发布白皮书:美国欲重返世界半导体霸主!
  3. 无法通过windows installer服务安装此安装程序包。您必须安装带有更新版本windows Installer服务的Windows
  4. 重温强化学习之无模型学习方法:蒙特卡洛方法
  5. nginx源码分析—数组结构ngx_array_t
  6. oracle脂肪分析仪,CEM推出油脂快速分析新技术
  7. null === undefined_【英】两个“非值”:undefined 和 null
  8. 在矩池云上使用A6000/3090跑ikatago说明
  9. 关于 exynos 4412 按键中断 异步通知
  10. 暴力破解-----token验证
  11. django的文档信息
  12. 中职计算机组装与维修知识点,中职计算机组装与维修的教学分析与对策
  13. win7自动锁定计算机快捷键,两种方法教你锁定Win7系统电脑计算机快捷键
  14. 走完离职流程心力交瘁,血泪教训:年终奖兑换期权要慎重,期权变现有风险,加班认定最管用的是加班申请记录!...
  15. html实现鼠标悬停效果实现
  16. dubbo 监控中心配置
  17. android app启动失败,Android应用App启动白屏(黑屏)问题解决
  18. 今日更新 | 955.WLB 不加班公司名单 | 新增5家公司
  19. python数组中最大元素_Python获取numpy数组中最大的5个元素(保持原顺序)
  20. 特斯拉model3中控屏怎么关_玩转特斯拉Model 3:那些隐藏的功能和技巧

热门文章

  1. 面试官:聊聊分布式事务,再说说解决方案!
  2. 十亿级流量下,我与Redis时延小突刺的战斗史
  3. 面试被问BIO、NIO、AIO的区别,怎么破?
  4. 一口气带你踩完五个 List 的大坑,真的是处处坑啊!
  5. 互联网10年,激战如梦
  6. 微服务治理实践:服务查询
  7. 为什么用了索引之后,查询就会变快?
  8. 2019年十大数据与分析技术趋势
  9. 飞书,成就组织和个人 让每一分努力都有意义!
  10. 人是被经验塑造的动物,一家公司也是