简体   繁体   中英

tornado: is BaseHandler.write blocking?

I have two requesthandler. One that delivers a huge amount auf data, the other only a few datasets.

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()

My Question :

Is the responding for loop blocking? When i request the small amount of data after a call of the huge handler, i have to wait, for the first one to be finished ...

write() does not block on the network (it just appends to a buffer), but you're not yielding anywhere so the entire loop must run to completion before any other task can run. I think the problem is not the write but the iteration - "for row in cursor" does not yield so either momoko has buffered the entire result set in memory or you are blocking while reading from the database. If the latter, you need to access the cursor in a non-blocking way. If the former, there may not be much you can do about it besides break the query up into smaller chunks. (you could occasionally call "yield gen.Task(self.flush)" during the loop, but this would prolong the time that the full amount is buffered in memory so it may not be advisable).

So, that 's the point. The for loop needs to complete.

What is about such an approach?

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM