如何基于 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
-
前言
首先,我们先介绍一下
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