如何在Tornado中使用Python3.4进行异步MySQL操作?

3 投票
1 回答
5585 浏览
提问于 2025-04-18 12:30

我现在使用的是Python3.4,想在Tornado中使用异步的MySQL客户端。我找到了一款叫torndb的工具,但看了它的源代码后,我觉得它不能进行异步的MySQL操作,因为它只是对MySQLdb这个包进行了封装。

那么,有没有办法在Tornado中实现异步的MySQL操作呢?

1 个回答

3

使用MySQL和Tornado的标准方法是用一组单独的进程来和MySQL沟通,然后用异步的HTTP请求来和这些进程交流(你可以参考这个链接中的第二个答案)。这些进程可以在同一台机器上,也可以在其他地方的应用服务器上。下面是一个简单的例子:

import json, sys, time
from MySQLdb import connect, cursors
from tornado import gen, httpclient, web, netutil, process, httpserver, ioloop

class BackendHandler(web.RequestHandler):   
    def get(self):
        time.sleep(1)  # simulate longer query
        cur = connect(db='tornado', user='root').cursor(cursors.DictCursor)
        cur.execute("SELECT * FROM foo")
        self.write(json.dumps(list(cur.fetchall())))

class FrontendHandler(web.RequestHandler):
    @gen.coroutine
    def get(self):
        http_client = httpclient.AsyncHTTPClient(max_clients=500)
        response = yield http_client.fetch("http://localhost:8001/foo")
        self.set_header("Content-Type", 'application/json')
        self.write(response.body)


if __name__ == "__main__":
    number_of_be_tasks = int(sys.argv[1]) if len(sys.argv) > 1 else 20
    number_of_fe_tasks = int(sys.argv[2]) if len(sys.argv) > 2 else 1
    fe_sockets = netutil.bind_sockets(8000)  # need to bind sockets
    be_sockets = netutil.bind_sockets(8001)  # before forking
    task_id = process.fork_processes(number_of_be_tasks + number_of_fe_tasks)
    if task_id < number_of_fe_tasks:
        handler_class = FrontendHandler
        sockets = fe_sockets
    else:
        handler_class = BackendHandler
        sockets = be_sockets
    httpserver.HTTPServer(web.Application([(r"/foo", handler_class)])
        ).add_sockets(sockets)
    ioloop.IOLoop.instance().start()

不过,如果你的网页服务器主要是直接和MySQL对话,那么Tornado的优势就不大了(因为你需要的进程数量和你想要的同时连接数是一样的)。在这种情况下,使用nginx+uwsgi+python可能会更好。Tornado真正擅长的是和多个后端服务器进行HTTP通信,可能还可以并行处理。

撰写回答