Python已经relase3.6版本了,尝试使用PY3来构建服务,由于比较熟悉Tornado,故测试一下tornado在Python3下的常见用法。
业务代码通常需要访问三方服务和数据库,因此针对异步的http和数据库io进行测试。
事件循环
Python3.5+ 的标准库asyncio提供了事件循环用来实现协程,并引入了async/await关键字语法以定义协程。Tornado通过yield生成器实现协程,它自身实现了一个事件循环。由于一些三方库都是基于asyncio进行,为了更好的使用python3新特效带来的异步IO,实际测试了Tornado在不同的事件循环中的性能,以及搭配三方库(motor,asyncpg,aiomysql)的方式。
tornado app基本结构
一个基本的tornado app代码如下:
import tornado.httpserver as httpserver
import tornado.ioloop as ioloop
import tornado.options as options
import tornado.web as web
options.parse_command_line()
class IndexHandler(web.RequestHandler):
def get(self):
self.finish(“It works”)
class App(web.Application):
def init(self):
settings = {
‘debug’: True
}
super(App, self).init(
handlers=[
(r’/’, IndexHandler)
],
**settings)
if name == ‘main’:
app = App()
server = httpserver.HTTPServer(app, xheaders=True)
server.listen(5010)
ioloop.IOLoop.instance().start()
使用tornado默认的事件循环驱动app,IOLoop会创建一个事件循环,用于响应epoll事件,并调用响应的handler处理请求。
异步http client
Tornado提供了一个异步的HTTPClient,用于handler中访问三方的api,即使当前的三方api访问被阻塞了,也不会阻塞tornado响应其他的handler。
class GenHttpHandler(web.RequestHandler):
@gen.coroutine
def get(self):
url = ‘http://127.0.0.1:5000/’
client = httpclient.AsyncHTTPClient()
resp = yield client.fetch(url)
print(resp.body)
self.finish(resp.body)
gen是tornado提供的协程模块。python3中还可以使用 async/await的语法
class AsyncHttpHandler(web.RequestHandler):
async def get(self):
url = ‘http://127.0.0.1:5000/’
client = httpclient.AsyncHTTPClient()
resp = await client.fetch(url)
print(resp.body)
self.finish(resp.body)
asyncio 事件循环
Aysnc定义协程方式基本符合tornado的协程,但是毕竟不是全兼容了。例如asyncio.sleep 将不会work。
class SleepHandler(web.RequestHandler):
async def get(self):
print(“hello tornado”)
await asyncio.sleep(5)
self.write(‘It works!’)
想要上面的asyncio.sleep 能够正常,需要替换I使用asyncio的事件循环替换ioloop。
if name == ‘main’:
tornado_asyncio.AsyncIOMainLoop().install()
app = App()
server = httpserver.HTTPServer(app, xheaders=T