クライアントが gevent-socketio と redis-py で構築された複数の Redis PubSub チャネルから更新を受信するリアルタイム Web アプリケーションがあります。
私は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)
私の理解では、新しい Greenlet を作成したり、サブスクリプションを解除したりせずにサブスクリプションを追加することはできません。
頻繁な購読と購読解除を効率的に処理するにはどうすればよいですか?
更新:私が構築しているのは、理論的には無限の 2D マップでの HTML5 リアルタイム MMO ゲームです。マップのサイズが大きいため、マップ全体の状態をブラウザに送信することはできません。そのため、マップはタイルに分割され、プレーヤーがマップをドラッグすると動的に読み込まれます (Google マップを考えてください)。
マップがドラッグされるたびに、クライアント/ブラウザーは、表示されたばかりのタイルの更新をサブスクライブし、少し遅れて、非表示になったタイルの更新のサブスクライブを解除します。サブスクリプションの変更は、プレイヤーごとに 1 秒に 1 回程度であるため、頻度は相対的です。
クライアントの数は(うまくいけば)多くなります。理論的には、すべてのプレイヤーがマップの同じ部分を見ることができるため、SUBSCRIBEとUNSUBSCRIBEは非常にコストがかかりO(N) where N is the number of clients already subscribed to a channel
ます。実際には、世界中に均等に分散されるため、これは問題になりません。
ただし、私の主な問題は、リッスン時に Python Redis PubSub 実装がブロックされることです。上記の例で red.listen() を呼び出すと、メッセージが到着するまでサブスクリプションを変更できなくなります。上記のコード例は、サブスクリプションごとに Redis への新しい接続を使用して新しい Greenlet を開始しますが、これはおそらく悪い考えです。