龙卷风:是BaseHandler.write阻塞?

时间:2013-12-23 14:30:29

标签: python tornado

我有两个requesthandler。一个提供大量的auf数据,另一个只提供一些数据集。

class HugeQueryHandler(BaseHandler):
    @gen.coroutine
    def get(self):
        try:
            cursor = yield momoko.Op(self.db.execute, 'SELECT * FROM huge_table;')
            for row in cursor:
                self.write('Query results: {} <br />'.format(row))
        except Exception as error:
            self.write(str(error))

        self.finish()

class SmallQueryHandler(BaseHandler):

    @gen.coroutine
    def get(self):
        try:
            cursor = yield momoko.Op(self.db.execute, 'SELECT * FROM small_table;')
            for row in cursor:
                self.write('Query results: {} <br />'.format(row))
        except Exception as error:
            self.write(str(error))

        self.finish()

我的问题

响应循环阻塞吗?当我在调用巨大的处理程序后请求少量数据时,我必须等待,第一个完成...

2 个答案:

答案 0 :(得分:0)

write()不会在网络上阻塞(它只是附加到缓冲区),但是你不会放弃任何地方,所以在任何其他任务可以运行之前,整个循环必须运行完成。我认为问题不在于写入,而是迭代 - “for cursor in cursor”不会产生,所以momoko将整个结果集缓存在内存中,或者在从数据库读取时阻塞。如果是后者,则需要以非阻塞方式访问游标。如果是前者,除了将查询分解为更小的块之外,可能没有太多可以解决的问题。 (你可以偶尔在循环中调用“yield gen.Task(self.flush)”,但是这会延长在内存中缓冲全部数量的时间,因此可能不合适。)

答案 1 :(得分:0)

所以,这就是重点。 for循环需要完成。

这种方法是什么?

class HugeQueryHandler(BaseHandler):

    executor = tornado.concurrent.futures.ThreadPoolExecutor(1)

    @tornado.concurrent.run_on_executor
    def generate_response(self, cursor):
        return "<br />".join("{}".format(row) for row in cursor)

    @tornado.web.asynchronous
    @gen.engine
    def get(self):
        try:
            cursor = yield momoko.Op(self.db.execute, 'SELECT * FROM huge_table;')
            res = yield self.generate_response(cursor)
            self.write(res)
        except Exception as error:
            self.write(str(error))
        self.finish()