大部分Web应用(包括咱们以前的例子)都是阻塞性质的,也就是说当一个请求被处理时,这个进程就会被挂起直至请求完成。在大多数状况下,Tornado处理的Web请求完成得足够快使得这个问题并不须要被关注。然而,对于那些须要一些时间来完成的操做(像大数据库的请求或外部API),这意味着应用程序被有效的锁定直至处理结束,很明显这在可扩展性上出现了问题。web
不过tornado给了咱们更好的方法来处理这种状况。应用程序在等待第一个处理完成的过程当中,让I/O循环打开以便服务于其余客户端,直处处理完成时启动一个请求并给予反馈,而再也不是等待请求完成的过程当中挂起进程。数据库
咱们首先构造一个阻塞性质的例子来看下:apache
在这个例子中咱们首先须要实例化一个HTTPClient类,而后调用对象的fetch方法。经过fetch方法咱们构建一个URLL来抓取阿里云根据地区名获取经纬度接口。网站会返回一个json的结果,咱们将这个json结果呈如今咱们的网页上json
经过阿里云查询成都的经纬度并发
咱们的代码构造以下:app
经过获取网页传递的参数a来获得从查询的城市,而且构造完整的URL。response获取到网页反馈的信息而且反馈到网页上异步
class indexHandler(tornado.web.RequestHandler):async
def get(self, *args, **kwargs):ide
query=self.get_argument('a').encode('utf-8')函数
client=tornado.httpclient.HTTPClient()
response=client.fetch("http://gc.ditu.aliyun.com/geocoding?"+urllib.urlencode({'a':query}))
body=json.loads(response.body)
self.write(response.body)
获得的结果以下。
从tornado的后台打印中看到整个的响应时延是96.78ms.
[I 171231 14:44:18 web:2063] 200 GET /?a=%E6%88%90%E9%83%BD (127.0.0.1) 96.78ms
到这里,咱们已经编写了一个请求阿里云反馈城市经纬的应用。可是只有一个请求也就是能够认为是单线程应用,若是咱们有多个请求的时候,性能会如何呢?
咱们须要使用一个测试工具来测试大量请求的时候性能表现。这里咱们用到siege工具进行测试。使用方法很简单:
siege http://127.0.0.1:8000/?a=成都 -c10 -t10s
参数的解释以下:-c表明的是设置的同时并发的用户数。
-c NUM, --concurrent=NUM
This option allows you to set the concurrent number of users. The
total number of users is technically limited to your computer's
resources.
You should not configure more users than your web server is
configured to handle. For example, the default apache configuration
is capped at 255 threads. If you run siege with -c 1024, then 769
siege users are left waiting for an apache handler.
For this reason, the default siege configuration is capped at 255
users. You can increase that number inside s
-t表明的是测试运行的时间,-t10s表明运行10秒的意思
-t NUMm, --time=NUMm
This option is similar to --reps but instead of specifying the
number of times each user should run, it specifies the amount of
time each should run.
The value format is "NUMm", where "NUM" is an amount of time and
the "m" modifier is either S, M, or H for seconds, minutes and
hours. To run siege for an hour, you could select any one of the
following combinations: -t3600S, -t60M, -t1H. The modifier is not
case sensitive, but it does require no space between the number and
itself.
执行结果以下:能够看到成功发送请求65次。不到10秒的时间平均响应时间达到了1.03m秒,
root@zhf-maple:/home/zhf/桌面# siege http://127.0.0.1:8000/?a=成都 -c10 -t10s
** SIEGE 4.0.2
** Preparing 10 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 65 hits
Availability: 74.71 %
Elapsed time: 9.27 secs
Data transferred: 0.01 MB
Response time: 1.03 secs
Transaction rate: 7.01 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 7.21
Successful transactions: 65
Failed transactions: 22
Longest transaction: 1.40
Shortest transaction: 0.47
咱们加大同时复用的次数:在这里设置为20个并发用法。能够看到平均相应时间直接翻倍成2.29秒
root@zhf-maple:/home/zhf/桌面# siege http://127.0.0.1:8000/?a=成都 -c20 -t10s
** SIEGE 4.0.2
** Preparing 20 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 70 hits
Availability: 76.92 %
Elapsed time: 9.89 secs
Data transferred: 0.01 MB
Response time: 2.29 secs
Transaction rate: 7.08 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 16.22
Successful transactions: 70
Failed transactions: 21
Longest transaction: 2.56
Shortest transaction: 0.10
若是将并发次数继续往上抬升能够看到响应时间跟随一块儿增长。当咱们增长到100个用户的时候,平均响应时间变成了6.12秒。
root@zhf-maple:/home/zhf/桌面# siege http://127.0.0.1:8000/?a=成都 -c100 -t10s
** SIEGE 4.0.2
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 71 hits
Availability: 78.02 %
Elapsed time: 9.49 secs
Data transferred: 0.01 MB
Response time: 6.12 secs
Transaction rate: 7.48 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 45.77
Successful transactions: 71
Failed transactions: 20
Longest transaction: 9.39
Shortest transaction: 0.16
这种增加的速度对于同时大量用户在线访问的时候确定是没法接收的。幸运的是,Tornado包含一个AsyncHTTPClient类,能够执行异步HTTP请求。代码修改以下。首先使用tornado.web.asynchronous装饰器并在fetch增长回调函数。这个回调函数将在HTTP请求完成时被调用。并用response做为参数。
class indexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self, *args, **kwargs):
query=self.get_argument('a').encode('utf-8')
client=tornado.httpclient.AsyncHTTPClient()
response=client.fetch("http://gc.ditu.aliyun.com/geocoding?"+urllib.urlencode({'a':query}),callback=self.on_response)
def on_response(self,response):
body=json.loads(response.body)
self.write(response.body)
self.finish()
咱们来看下性能如何:一样设置-c10 -t10s。响应时间从以前的1.03秒降低到0.19秒。总共传输的次数以及每秒传输的次数也增长
root@zhf-maple:/home/zhf/桌面# siege http://127.0.0.1:8003/?a=成都 -c10 -t10s
** SIEGE 4.0.2
** Preparing 10 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 211 hits
Availability: 100.00 %
Elapsed time: 9.36 secs
Data transferred: 0.00 MB
Response time: 0.19 secs
Transaction rate: 22.54 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 4.39
Successful transactions: 211
Failed transactions: 0
Longest transaction: 0.25
Shortest transaction: 0.17
并发20个用户的时候,响应时间从2.29秒降低为0.22秒
root@zhf-maple:/home/zhf/桌面# siege http://127.0.0.1:8003/?a=成都 -c20 -t10s
** SIEGE 4.0.2
** Preparing 20 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 389 hits
Availability: 100.00 %
Elapsed time: 9.23 secs
Data transferred: 0.01 MB
Response time: 0.22 secs
Transaction rate: 42.15 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 9.38
Successful transactions: 389
Failed transactions: 0
Longest transaction: 0.44
Shortest transaction: 0.1
并发100个用户的时候,响应时间从6.12变成了1.99秒。且成功传输次数增加到了362次
root@zhf-maple:/home/zhf/桌面# siege http://127.0.0.1:8003/?a=成都 -c100 -t10s
** SIEGE 4.0.2
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 362 hits
Availability: 100.00 %
Elapsed time: 9.19 secs
Data transferred: 0.01 MB
Response time: 1.99 secs
Transaction rate: 39.39 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 78.53
Successful transactions: 362
Failed transactions: 0
Longest transaction: 3.26
Shortest transaction: 0.21
从这里能够看到,并发带来的性能提高是巨大的。特别是在多用户同时访问的情下。下一章将介绍并发的原理。