我用龙卷风实现REST api,并希望它是非阻塞的。
目前,与问题相关的代码如下:
class ReprsHandler(web.RequestHandler):
async def get(self, name):
db = await dbf.create_handler()
if 'id' in list(self.request.query_arguments.keys()):
db_future = asyncio.ensure_future(db.get_repr(name, self.get_query_argument('id')))
else:
db_future = asyncio.ensure_future(db.get_reprs(name))
result = await db_future
response = result.toSerializedStream()
self.set_status(HTTPStatus.OK)
self.write(response)
self.set_header('Content-Type', 'text/plain')
self.finish()
class App(object):
def __init__(self, loop):
self.server_app = web.Application(
handlers=[
(r"/api/v1/([a-zA-Z0-9_-]+)/reprs", ReprsHandler),
]
)
def main():
AsyncIOMainLoop().install()
loop = asyncio.get_event_loop()
app = App(loop)
server = tornado.httpserver.HTTPServer(app.server_app, max_body_size=config['max_upload_size'], max_buffer_size=config['max_upload_size'])
server.bind(config['server_port'])
server.start()
loop.run_forever()
简单的代码,但数据非常大,所以发送所有内容大约需要3到4分钟。
我希望处理程序的逻辑和网络IO都是非阻塞的,但它会在发送数据作为响应时阻塞服务器网络。逻辑很好。他们不会阻止其他请求。
详细说明:
可能有什么问题?我不知道是什么造成了这个问题。
答案 0 :(得分:1)
由于您提到result.toSerializedStream()
腌制数据。所以,是的,你是正确的,阻止是因为网络io。
为避免这种情况,您可以在数据块中发送数据,并在每self.flush()
后调用self.write()
。调用flush
会将响应写入网络。由于您可以在await
上flush
,因此在将数据写入网络套接字之前,协程将暂停,服务器不会阻止。这允许其他处理程序异步运行。
代码示例:
async def get(self, name):
...
response = result.toSerializedStream()
chunk_size = 1024 * 1024 * 10 # 10 MiB
start_byte = 0
while True:
chunk = response[start_byte : start_byte + chunk_size]
if not chunk:
break
self.write(chunk)
await self.flush() # wait while data is flushed to network
start_byte += chunk_size # move start_byte forward
重要:强>
这里要注意的一件重要事情是self.flush()
非常快。如果您要将小数据刷新到网络,await
延迟非常小,以至于协程会不间断地继续运行,从而阻塞服务器。
在上面的示例代码中,我已将chunk_size
设置为10 MiB
,但如果您的计算机速度很快,则await
延迟将非常非常小,并且在发送整个数据之前,循环可以不间断地运行。
我建议您根据需要增加或减少chunk_size
值。
进一步改善建议:
所有数据都在内存中。既然你的处理程序是异步的并且没有阻止,如果ReprsHandler
有另一个请求,这将导致更多的数据存储在内存中。如果有越来越多的请求进入,那么你可以告诉我们将会发生什么。
为了避免这种情况,您可以将其转储到文件中,而不是在内存中搜索数据。然后在你的处理程序中只需open
该文件并以块的形式读取并发送它。
答案 1 :(得分:0)
行。这个问题太愚蠢了。
我期待这种非阻塞API能够作为并行网络工作,因此整个网络不会互相打断。并不是龙卷风的设计目标。它显然是非阻塞的,但仍然是单线程的。