使用redis-py更改PubSub订阅

时间:2012-04-19 16:45:13

标签: python redis socket.io publish-subscribe gevent

我有一个实时webapp,客户端从多个Redis PubSub频道接收更新,使用gevent-socketio和redis-py构建。

我正在查看views.py, l.26示例中的django-tictactoe。 当客户端发送频道的订阅消息时,它会生成一个新的greenlet。然后,greenlet订阅Redis PubSub频道并阻止,直到收到消息。

class GameNamespace(BaseNamespace):
    def listener(self, chan):
            red = redis.StrictRedis(REDIS_HOST)
            red = red.pubsub()
            red.subscribe(chan)

            print 'subscribed on chan ', chan

            while True:
                for i in red.listen():
                    self.send({'message': i}, json=True)

    def recv_message(self, message):
        action, pk = message.split(':')

        if action == 'subscribe':
            Greenlet.spawn(self.listener, pk)

根据我的理解,如果不生成新的Greenlets或取消订阅订阅,就无法添加订阅。

您如何以有效的方式处理频繁的订阅和取消订阅?

更新:我正在构建的是一个理论上无限的2D地图上的HTML5实时MMO游戏。由于地图的大小,无法将整个地图的状态发送到浏览器。因此,地图以瓷砖分区,当玩家拖动地图时动态加载(想想谷歌地图)。

每当拖动地图时,客户端/浏览器都会订阅刚刚变为可见的磁贴的更新,并在短暂延迟后取消订阅不可见的磁贴更新。订阅的更改可能每个玩家每秒发生一次,因此频繁是相对的。

客户数量(希望)很大。从理论上讲,所有玩家都可以查看地图的相同部分,使SUBSCRIBEUNSUBSCRIBE非常昂贵,因为它们是“O(N) where N is the number of clients already subscribed to a channel”。在实践中,它将在全世界均匀分布,所以这应该不是问题。

但是,我的主要问题是Python Redis PubSub实现会阻止侦听。一旦我在上面的例子中调用red.listen(),我就不能再更改订阅了到达。上面的示例代码启动了一个新的Greenlet,每个订阅都有一个与Redis的新连接,这可能是一个坏主意。

1 个答案:

答案 0 :(得分:0)

您没有说明订阅之间的分区基本原理/要求是什么,即哪些信息流过必须与其他订阅分开的订阅,因此很难明确回答。我会做一些假设...

如果您有少量或固定数量的客户端管理多个订阅,那么通过单个长期订阅多路复用许多不同事件可能会更好,Redis客户端会对最终事件使用者进行多路分解。从Redis的角度来看,这种方法可能更有效,而不是为每个消费者重复设置和拆除订阅。

这样的方案需要发布者的一些额外情报,以便他们可以为每条消息选择正确的队列,但有时可以很容易地实现,例如,通过散列客户端ID模N,其中N是发布/子队列的数量。

我希望这与您提出的问题有关...