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),然后用户就可以通过类的实例来 向主题发布或接收消息。

代码清单16-1 使用发布与订阅功能实现的广播系统:/pubsub/boardcast.py
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!'