【发布时间】:2015-10-18 15:27:36
【问题描述】:
我目前正在使用aiohttp 来了解它作为具有 websocket 连接的移动应用程序的服务器应用程序的性能。
这是一个简单的“Hello world”示例 (as gist here):
import asyncio
import aiohttp
from aiohttp import web
class WebsocketEchoHandler:
@asyncio.coroutine
def __call__(self, request):
ws = web.WebSocketResponse()
ws.start(request)
print('Connection opened')
try:
while True:
msg = yield from ws.receive()
ws.send_str(msg.data + '/answer')
except:
pass
finally:
print('Connection closed')
return ws
if __name__ == "__main__":
app = aiohttp.web.Application()
app.router.add_route('GET', '/ws', WebsocketEchoHandler())
loop = asyncio.get_event_loop()
handler = app.make_handler()
f = loop.create_server(
handler,
'127.0.0.1',
8080,
)
srv = loop.run_until_complete(f)
print("Server started at {sock[0]}:{sock[1]}".format(
sock=srv.sockets[0].getsockname()
))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
loop.run_until_complete(handler.finish_connections(1.0))
srv.close()
loop.run_until_complete(srv.wait_closed())
loop.run_until_complete(app.finish())
loop.close()
问题
现在我想使用下面描述的结构(节点服务器 = python aiohttp)。更具体地说,使用Redis Pub/Sub 机制和asyncio-redis 在我的WebsocketEchoHandler 中读取和写入websocket 连接和Redis。
WebsocketEchoHandler 是一个简单的死循环,所以我不确定应该如何完成。使用Tornado 和brükva 我只会使用回调。
额外的(也许是离题的)问题
由于我已经在使用Redis,我应该采取两种方法中的哪一种:
- 就像在“经典”网络应用中一样,对所有内容都有一个控制器/视图,使用 Redis 仅用于消息传递等。
- Web 应用程序应该只是客户端和Redis 之间的一层,也用作任务队列(最简单的Python RQ)。每个请求都应委托给工作人员。
编辑
图片来自http://goldfirestudios.com/blog/136/Horizontally-Scaling-Node.js-and-WebSockets-with-Redis
编辑 2
看来我需要澄清一下。
- 上面显示了仅限 Websocket 的处理程序
-
Redis Pub/Sub 处理程序可能如下所示:
class WebsocketEchoHandler: @asyncio.coroutine def __call__(self, request): ws = web.WebSocketResponse() ws.start(request) connection = yield from asyncio_redis.Connection.create(host='127.0.0.1', port=6379) subscriber = yield from connection.start_subscribe() yield from subscriber.subscribe(['ch1', 'ch2']) print('Connection opened') try: while True: msg = yield from subscriber.next_published() ws.send_str(msg.value + '/answer') except: pass finally: print('Connection closed') return ws这个处理程序只是订阅 Redis 通道 ch1 和 ch2 并将每个从这些通道接收到的消息发送到 websocket。
-
我想要这个处理程序:
class WebsocketEchoHandler: @asyncio.coroutine def __call__(self, request): ws = web.WebSocketResponse() ws.start(request) connection = yield from asyncio_redis.Connection.create(host='127.0.0.1', port=6379) subscriber = yield from connection.start_subscribe() yield from subscriber.subscribe(['ch1', 'ch2']) print('Connection opened') try: while True: # If message recived from redis OR from websocket msg_ws = yield from ws.receive() msg_redis = yield from subscriber.next_published() if msg_ws: # push to redis / do something else self.on_msg_from_ws(msg_ws) if msg_redis: self.on_msg_from_redis(msg_redis) except: pass finally: print('Connection closed') return ws但以下代码总是按顺序调用,因此从 websocket 读取会阻止从 Redis 读取:
msg_ws = yield from ws.receive() msg_redis = yield from subscriber.next_published()
我希望在 事件 上完成阅读,其中 事件 是从两个来源之一收到的消息。
【问题讨论】:
-
对不起,我不关注。这正是你的问题?
-
@AndrewSvetlov 已更新。
标签: python redis python-asyncio aiohttp