Tornado 异步非阻塞 实验

目前用到的都是同步请求。当遇到查数据库等耗时操作的时候,请求会一直被阻塞。

实验

我们使用sql语句cmds = "select sleep(1)"来模拟长时间的数据库查询。

使用siege做压测。

另外,还可以用ab压测:
ab -c 10 -n 10 :8888/asynctask?t=1

同步 V.S. Tornado-MySQL异步

只贴出handler部分的代码。

其中IndexHandler为同步请求,路由为‘/’

AsynHandler为异步请求,路由为‘/asyn’

cmds = "select sleep(1)" MYSQL_POOL = pools.Pool(dict(host=host, port=port, user=usr, passwd=passwd, db=db) , max_idle_connections=5, max_open_connections=10) class IndexHandler(tornado.web.RequestHandler): def get(self): conn = MySQLdb.connect(host, usr, passwd, db, port) cur = conn.cursor() cur.execute(cmds) rep = cur.fetchall() self.write({'res': rep}) class AsynHandler(tornado.web.RequestHandler): @tornado.web.asynchronous @tornado.gen.coroutine def get(self): cur = yield MYSQL_POOL.execute(cmds) self.write({'res': cur.fetchall()}) self.finish()

在同步的情况下,浏览器发起请求后会被阻塞,一直等到上一条查询完了,才能接受下一个请求。假设数据库请求耗时1s,同时发起调用的话,第1个请求会在大概1s后得到响应,第2个请求会在大概2s后得到响应。。。

在异步的情况下,则不需要等待数据库查询结束,可以在得到结果前接收下一个请求。假设数据库请求耗时1s,同时发起调用的话,理想情况下所有请求都会在1s后得到响应。

我们参照官网使用工具siege进行测试

模拟10个用户同时发出1次请求:

同步请求的测试结果是:

siege 10.9.40.173:8888 -c10 -r1 ** SIEGE 3.0.8 ** Preparing 10 concurrent users for battle. The server is now under siege.. done. Transactions: 10 hits Availability: 100.00 % Elapsed time: 10.06 secs Data transferred: 0.00 MB Response time: 5.12 secs Transaction rate: 0.99 trans/sec Throughput: 0.00 MB/sec Concurrency: 5.09 Successful transactions: 10 Failed transactions: 0 Longest transaction: 10.05 Shortest transaction: 1.00

总共用时10.06 secs,平均响应时间是5.12 secs,跟我们预想的一样,最快的响应是1 secs(第一个请求),最慢的响应是10 secs(最后一个请求)。平均耗时大概是(1+2+3+…+10)/10=5.5 secs

而异步请求的测试结果是:

siege 10.9.40.173:8888/asyn -c10 -r1 ** SIEGE 3.0.8 ** Preparing 10 concurrent users for battle. The server is now under siege.. done. Transactions: 10 hits Availability: 100.00 % Elapsed time: 2.04 secs Data transferred: 0.00 MB Response time: 1.03 secs Transaction rate: 4.90 trans/sec Throughput: 0.00 MB/sec Concurrency: 5.04 Successful transactions: 10 Failed transactions: 0 Longest transaction: 1.06 Shortest transaction: 1.01

总共用时2.04 secs,平均响应时间是1.03 secs,达到了异步请求的理论速度。最快的响应是1.01 secs,最慢的响应也才1.06 secs。

不需要返回结果的异步请求 class AsynPingNoResHandler(tornado.web.RequestHandler): @tornado.web.asynchronous @tornado.gen.coroutine def get(self, *args, **kwargs): tornado.ioloop.IOLoop.instance().add_timeout(1, callback=functools.partial(self.ping, 'www.baidu.co$ # do something others self.finish('It works') @tornado.gen.coroutine def ping(self, url): os.system("ping -c 2 {}".format(url)) return 'after'

需要返回结果的异步请求

再来一个利用tornado.gen.coroutine的例子,我参考伯乐在线的文章做的实验,但是没有得到文章的结果:

class AsyncTaskHandler(tornado.web.RequestHandler): @tornado.web.asynchronous @tornado.gen.coroutine def get(self): t = self.get_argument('t') response = yield tornado.gen.Task(self.query, t) #print 'response', response self.write({'res': response}) self.finish() @tornado.gen.coroutine def query(self, t): conn = MySQLdb.connect(host, usr, passwd, db, port) cur = conn.cursor() cur.execute(cmdsn % t) rep = cur.fetchall() return rep

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/4b9fdbd2c2bd83771e0fdede64667ac4.html