??mysql
Tornado 標榜的是 asynchronous 和 non-blocking,然而,不少時候一不當心一不講究就會把整個 tornado 阻塞住,特別是作 MySQL 操做時。本文簡述兩種在 tornado 中異步無阻塞地使用 MySQL 的方法。web
常見的阻塞狀況sql
class Handler(tornado.web.RequestHandler): def get(self): connection = pymysql.connect() # 鏈接數據庫的相關參數省略 with connection.cursor() as cursor: sql = '這裏應該有一條SQL查詢語句' cursor.execute(sql) result = cursor.fetchone() self.write(str(result['id']))
以上這種情景,tornado 會在 pymysql.connect() 和 cursor.execute(sql) 的地方阻塞住,沒法響應其餘 request。數據庫
無阻塞方案1:使用 Tornado-MySQL 做者不維護,不用爲好。app
無阻塞方案2:使用 Celery異步
Celery 是一個異步的任務隊列,它能很方便地支持分佈式擴展,於是很適合將 tornado 中的長時間的阻塞工做交由 Celery 來完成。 而要 Celery 配合 Tornado 一塊兒工做,須要藉助一個名爲 tornado-celery 請戳 pypi 頁面的包。async
看例子,首先是 tornado handler 的代碼:分佈式
import tornado.gen import tornado.web import tcelery import mysql_task tcelery.setup_nonblocking_producer() class Handler(tornado.web.RequestHandler): @tornado.web.asynchronous @tornado.gen.coroutine def get(self): result = yield tornado.gen.Task(mysql_task.mysql_test.apply_async) self.write(result) self.finish()
而具體操做 MySQL 的部分則擺在 mysql_task.py 文件中。至於 celery worker 的寫法這裏就省略掉了。tornado
特別須要注意的是:tornado-celery 目前只支持 AMQP 的 backend。fetch