如何基于 Channel 实现多路复用 #3260
limingxinleo
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
前言
首先,我们先介绍一下
Swoole\Coroutine\Client
的一个限制,那便是同一个连接,不允许同时被两个协程绑定,我们可以进行以下测试。当我们执行以上代码,就会抛出以下错误
但我们稍微改动一下代码,就不会再次报错,代码如下
可见,我们只需要让
recv
在一个协程里循环调用,然后再根据收包发到不同的Channel
当中,这样我们就可以多个协程复用同一个连接。包体设计
接下来的事情就很简单了,我们设计一个十分简单的包结构。包头为使用 pack N 打包的包体长度,包体为 pack N 打包的 Channel ID 和 数据体。
因为 Swoole 中分包规则已经实现,所以我们可以简单的配置一下实现上述效果
接下来我们只需要实现包体的 打包 和 解包功能即可,我们可以实现一个十分简单的打包器。
服务端
服务端的设计就尤为简单了,因为 Channel 机制主要是给 客户端使用,所以服务端解包之后,原封不动的将 ChannelID 和 数据返回即可。
客户端
客户端相比而言,就要麻烦一些。我们需要创建一个 Channel 存储需要 发送的数据,还需要设计一个 Channel Map 存储各个 ID 返回的数据,这样方便 recv 时,直接使用 Channel::pop() 获得数据,这样一来就可以很方便的将 业务客户端与实际客户端进行解耦。
下述代码中,我们创建了两个协程,循环调用
Client::send
和Client::recv
方法。实现组件
最后,根据上述的想法,我们实现了以下两个组件
multiplex
multiplex-socket
随手写了两段代码,对多路复用和连接池进行测试,我们创建 10000 个协程,同时调用服务端,当服务端接收到数据,立马返回的情况下
二者差距不大,完全结束都在 0.3-0.5 秒之间。
但当我们在返回数据前,睡眠 10 毫秒的情况下,多路复用所用的时间要低于连接池的十分之一。
不仅速度更快,多路复用的连接,从始至终只用到 1 个,但连接池却起了 100 个连接,综合来说,多路复用要比使用连接池表现的更加优秀。
示例
客户端
服务端
Beta Was this translation helpful? Give feedback.
All reactions