swoole mysql 并发_通过swoole协程实现并发编程

目前的Swoole 内置了丰富的协程组件供开发者直接调用以便快速实现异步非阻塞的并发编程,省去了开发者自己实现相应底层代码的麻烦:

TCP/UDP Client:Swoole\Coroutine\Client

TCP/UDP Server:Swoole\Coroutine\Server

HTTP/WebSocket Client:Swoole\Coroutine\HTTP\Client

HTTP/WebSocket Server:Swoole\Coroutine\HTTP\Server

HTTP2 Client:Swoole\Coroutine\HTTP2\Client

Redis Client:Swoole\Coroutine\Redis

Mysql Client:Swoole\Coroutine\MySQL

PostgreSQL Client:Swoole\Coroutine\PostgreSQL

在协程 Server 中使用对应的协程版 Client 来实现全异步 Server,同时 Swoole 提供了协程工具集:Swoole\Coroutine,提供了获取当前协程ID、反射调用等能力。

通过 setDefer 机制实现并发编程

我们以 Redis 和 MySQL 客户端请求为例,使用上述 Swoole\Coroutine\Redis 和 Swoole\Coroutine\MySQL 组件,可以实现异步 Redis 和 MySQL 客户端:

$server = new \Swoole\Http\Server('127.0.0.1', 9588);

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

var_dump(time());

$mysql = new Swoole\Coroutine\MySQL();

$mysql->connect([

'host' => '127.0.0.1',

'user' => 'root',

'password' => 'root',

'database' => 'laravel58',

]);

$mysql->setDefer();

$mysql->query('select sleep(3)');

var_dump(time());

$redis1 = new Swoole\Coroutine\Redis();

$redis1->connect('127.0.0.1', 6379);

$redis1->setDefer();

$redis1->set('hello', 'world');

var_dump(time());

$redis2 = new Swoole\Coroutine\Redis();

$redis2->connect('127.0.0.1', 6379);

$redis2->setDefer();

$redis2->get('hello');

$result1 = $mysql->recv();

$result2 = $redis2->recv();

var_dump($result1, $result2, time());

$response->end('Request Finish: ' . time());

});

$server->start();

由于 Swoole 会在 TCP Server 和 HTTP Server 回调函数中会自动开启协程,所以不需要显式通过 go 关键字启动协程,然后我们可以在回调函数中使用 MySQL 和 Redis 客户端协程组件发起请求。

要理解上述代码的运行原理,需要先了解协程的 setDefer 机制,绝大部分协程组件都支持 setDefer,该机制可以将请求响应式的接口拆分为两个步骤:先发送数据, 再并发收取响应结果。

由于大多数情况下,「建立连接和发送数据的耗时」相较于「等待响应的耗时」来说可以忽略不计, 所以可以简单理解为 defer 模式下, 多个客户端的请求响应是并发的(实际上只有接收响应是并发的,建立连接和发送请求是串行的)。

以上述代码为例,设置 setDefer(true) 后,通过 Redis 或 MySQL 客户端发起请求,将不再等待服务器返回结果,而是在发送请求之后,立即返回 true。在此之后可以继续发起其他 Redis、MySQL 请求,最后再使用 recv() 方法接收响应内容。

我们将上述代码保存到 coroutine/http.php,然后在终端启动这个 HTTP 服务端:

php coroutine/http.php

接下来,在 Postman 中对服务端发起请求,会在等待几秒后看到返回的响应内容:

前三个时间分别是 mysql、redis1、redis2 三个客户端发起请求的时间,可以看到,尽管 mysql 中会休眠 3 秒,但是通过 defer 机制实现了三个请求的并发执行。

通过子协程+通道实现并发编程

除了 setDefer 机制外,Swoole 还支持通过子协程+通道实现并发编程,下面我们通过子协程+通道的方式来改写上面的代码实现:

$server = new \Swoole\Http\Server('127.0.0.1', 9588);

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

$channel = new \Swoole\Coroutine\Channel(3);

go(function () use ($channel) {

var_dump(time());

$mysql = new Swoole\Coroutine\MySQL();

$mysql->connect([

'host' => '127.0.0.1',

'user' => 'root',

'password' => 'root',

'database' => 'laravel58',

]);

$result = $mysql->query('select sleep(3)');

$channel->push($result);

});

go(function () use ($channel) {

var_dump(time());

$redis1 = new Swoole\Coroutine\Redis();

$redis1->connect('127.0.0.1', 6379);

$result = $redis1->set('hello', 'world');

$channel->push($result);

});

go(function () use ($channel) {

var_dump(time());

$redis2 = new Swoole\Coroutine\Redis();

$redis2->connect('127.0.0.1', 6379);

$result = $redis2->get('hello');

$channel->push($result);

});

$results = [];

for ($i = 0; $i < 3; $i++) {

$results[] = $channel->pop();

}

$response->end(json_encode([

'data' => $results,

'time' => time()

]));

});

$server->start();

我们将 MySQL 和 Redis 客户端连接请求调用改写为通过三个子协程实现,同时去掉 setDefer 设置,因为这三个子协程已经是并发调用了,此外,由于三个子协程之间数据是相互隔离的,所以我们通过 Swoole\Coroutine\Channel (即通道)实现协程之间的数据共享和通信,初始化其缓冲空间为 3,然后通过 use 方式将其引入到子协程中,把响应结果通过 push 方法放到 Channel 里面,接下来在服务端 onRequest 回调函数末尾通过一个循环将 Channel 中的数据通过 pop 方法依次取出来放到数组 $results 中,最后通过 $response->end() 方法将结果以 JSON 格式返回给客户端。

我们将上述代码保存到 coroutine/http2.php,然后在终端通过如下命令启动这个新的 HTTP 服务端:

php coroutine/http2.php

还是在 Postman 中请求这个服务端,将响应格式调整为 JSON,会看到结果如下:

由于 MySQL 请求执行耗时最长,所以位置最靠后。在启动服务器的终端,可以看到打印出的三个客户端请求时间,完全一致,说明它们是并发执行的:

显然,通过子协程 + 通道还可以很方便的实现 Redis、MySQL 连接池。以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家或者 知乎专栏PHP7进阶架构师​zhuanlan.zhihu.com209abf2120702c8769f6190220edc737.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swoole是一个为PHP用C和C++编写的基于事件的高性能异步&协程并行网络通信引擎。同时也是PHP的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询。 Swoole内置了Http/WebSocket服务器端/客户端、Http2.0服务器端。 Swoole底层内置了异步非阻塞、多线程的网络IO服务器。PHP程序员仅需处理事件回调即可,无需关心底层。与Nginx/Tornado/Node.js等全异步的框架不同,Swoole既支持全异步,也支持同步。 除了异步IO的支持之外,Swoole为PHP多进程的模式设计了多个并发数据结构和IPC通信机制,可以大大简化多进程并发编程的工作。其中包括了并发原子计数器,并发HashTable,Channel,Lock,进程间通信IPC等丰富的功能特性。 Swoole从2.0版本开始支持了内置协程,可以使用完全同步的代码实现异步程序。PHP代码无需额外增加任何关键词,底层自动进行协程调度,实现异步。 Swoole可以广泛应用于互联网、移动通信、企业软件、网络游戏、物联网、车联网、智能家庭等领域。 使用PHP+Swoole作为网络通信框架,可以使企业IT研发团队的效率大大提升,更加专注于开发创新产品。 Swoole是开源免费的自由软件,授权协议是Apache2.0。企业和个人开发者均可免费使用Swoole的代码,并且在Swoole之上所作的修改可用于商业产品,无需开源(注:必须保留原作者的版权声明)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值