PUBSUB:查看发布与订阅的相关信息
通过使用PUBSUB命令,用户可以查看与发布、订阅有关的各种信息。 PUBSUB命令目前共有3个子命令可用,这3个子命令可以分别用于查看 不同的信息,接下来将分别介绍这3个子命令。
查看被订阅的频道
用户可以通过执行PUBSUB CHANNELS命令来列出目前被订阅的所有频 道,如果给定了可选的pattern参数,那么命令只会列出与给定模式相 匹配的频道:
PUBSUB CHANNELS [pattern]
作为例子,以下代码展示了该如何列出目前被订阅的所有频道:
redis> PUBSUB CHANNELS
1) "news.sport"
2) "news.it"
3) "notification.new_email"
4) "chat.python"
而以下代码则展示了如何列出所有以"news."开头的被订阅频道:
redis> PUBSUB CHANNELS "news.*"
1) "news.sport"
2) "news.it"
查看频道的订阅者数量
用户可以通过执行PUBSUB NUMSUB命令,查看任意多个给定频道的订阅者数量:
PUBSUB NUMSUB [channel channel ...]
举个例子,如果我们要查看 "news.it"、"news.sport" 和 "notification.new_email" 这3个频道的订阅者数量,那么可以执行以下命令:
redis> PUBSUB NUMSUB "news.it" "news.sport" "notification.new_email"
1) "news.it"
2) (integer) 2 -- "news.it"频道有2个订阅者
3) "news.sport"
4) (integer) 1 -- "news.sport"频道有1个订阅者
5) "notification.new_email"
6) (integer) 2 -- "notification.new_email"频道有2个订阅者
查看被订阅模式的总数量
通过执行PUBSUB NUMPAT命令,用户可以看到目前被订阅模式的总数量:
PUBSUB NUMPAT
比如以下代码就显示了服务器目前共有3个模式被订阅:
redis> PUBSUB NUMPAT
(integer) 3
其他信息
-
复杂度:PUBSUB CHANNELS命令的复杂度为O(N),其中N为服务器目前被订阅的频道总数量;PUBSUB NUMSUB命令的复杂度为O(N),其中 N 为用户给定的频道数量;PUBSUB NUMPAT命令的复杂度为O(1)。
-
版本要求:PUBSUB命令的3个子命令都从Redis 2.8.0版本开始可用。
示例:广播系统
Redis发布与订阅功能的其中一种应用,也是最常见的应用之一,就是 构建广播系统。这种系统能够将发布者发布的消息发送给任意多个订 阅者,这些订阅者通过监听的方式等待并获取消息。
通过使用广播系统,我们可以实现当前在即时聊天软件中非常常见的 多客户端消息收发功能:用户可以在计算机、手机、电视或者其他终 端上登录自己的账号,每当有人向用户发送消息的时候,消息就会在 多个终端上面显示。
代码清单16-1展示了一个使用发布与订阅功能实现的广播系统 Boardcast类,这个类在实例化的时候要求用户给定一个Redis客户端 以及一个用户关心的主题(topic),然后用户就可以通过类的实例来 向主题发布或接收消息。
class Boardcast:
def __init__(self, client, topic):
self.client = client
self.topic = topic
self.pubsub = self.client.pubsub()
self.pubsub.subscribe(self.topic)
# 丢弃频道的订阅消息
# 为了确保程序能收到订阅消息,故设置一秒钟的超时时限
self.pubsub.get_message(timeout=1)
def publish(self, content):
"""
针对主题发布给定的内容。
"""
self.client.publish(self.topic, content)
def listen(self, timeout=0):
"""
在给定的时限内监听与主题有关的内容。
"""
result = self.pubsub.get_message(timeout=timeout)
if result is not None:
return result["data"] # 只返回消息正文
def status(self):
"""
查看主题当前的订阅量。
"""
result = self.client.pubsub_numsub(self.topic)
return result[0][1] # 只返回订阅量,丢弃频道的名字
def close(self):
"""
停止广播。
"""
self.pubsub.unsubscribe(self.topic)
在下面的代码中,我们将使用几个不同的订阅者对象来模拟不同的终 端,当发布者jack向主题chat::peter发送问候消息时,所有订阅者 都会收到相同的消息:
>>> from redis import Redis
>>> from boardcast import Boardcast
>>> # 创建客户端
>>> client = Redis(decode_responses=True)
>>> # 创建订阅者对象
>>> pc = Boardcast(client, "chat::peter")
>>> mac = Boardcast(client, "chat::peter")
>>> phone = Boardcast(client, "chat::peter")
>>> # 创建发布者对象
>>> jack = Boardcast(client, "chat::peter")
>>> # 发布消息
>>> jack.publish("Good morning, peter!")
>>> # 各个订阅者分别接收消息
>>> pc.listen()
'Good morning, peter!'
>>> mac.listen()
'Good morning, peter!'
>>> phone.listen()
'Good morning, peter!'