我有一个实时 web 应用程序,客户端从多个 Redis PubSub 频道接收更新,这些频道使用 gevent-socketio 和 redis-py 构建。
我正在查看django-tictactoe示例中的views.py, l.26 。当客户端为频道发送订阅消息时,它会生成一个新的 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 游戏。由于地图的大小,无法将整个地图的状态发送到浏览器。因此,地图被划分为在玩家拖动地图时动态加载的图块(想想谷歌地图)。
每当拖动地图时,客户端/浏览器都会订阅刚刚变得可见的图块的更新,并在短暂延迟后取消订阅变得不可见的图块的更新。订阅的更改应该每名玩家每秒发生一次,所以频繁是相对的。
客户的数量(希望)会很大。理论上,所有玩家都可以查看地图的同一部分,这使得SUBSCRIBE和UNSUBSCRIBE非常昂贵,因为它们是“ O(N) where N is the number of clients already subscribed to a channel
”。在实践中,它会均匀分布在世界各地,所以这应该不是问题。
但是,我的主要问题是 Python Redis PubSub 实现在监听时阻塞。在上面的示例中调用 red.listen() 后,在消息到达之前,我无法再更改订阅。上面的示例代码启动了一个新的 Greenlet,每个订阅都有一个到 Redis 的新连接,这可能是个坏主意。