python语言一直以开发效率高著称,被普遍地应用于自动化领域:python
可是由于其也具备以下两个特征:git
前者致使其性能自然就被编译型语言在性能上落后了许多。然后者则在多核并行计算时代,极大的限制了python的应用场景。github
可是经过合理的web框架,则可使用python扬长避短,仍然可以在多核并行时代须保持其高效开发的生产力同时,在性能上也有出色表现。例如,tornado框架。web
tornado框架主要作了以下几件事:apache
基于python语言的web框架众多,可是主流的有“Django”和“Tornado”基本上能够表明了它们的实现理念。django
由于本文的重点是对 同步 和 异步 进行对比。因此关于不一样web框架的性能对比实验,就引用一位网友的帖子的实验结果吧。编程
参考文章 [1]:轻量级web server Tornado代码分析浏览器
此文章有些部分写得比较简略,可是咱们先大胆的作一下假设,做者是使用不一样的python的web框架对最基本的 HelloWorld 代码进行了实现。安全
参考的Tornado实现以下:bash
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
最后使用 Apache Benchmark (ab),在另一台机器上使用了以下指令进行负载测试:
ab -n 100000 -c 25 http://10.0.1.x/
在 AMD Opteron 2.4GHz 的四核机器上,结果以下图所示:
根据引文做者的观点:tornado是完虐其它的web框架的。
本文点评:此实验只是暂时让大伙创建一下宏观的对不一样的web框架的性能的认识,至于可信度是存疑的,由于实验报告写得不太规范,细节省略太多。本文的观点是,若是都是采用同步的的写法,tornado和django的性能差别应该没有那么大的。固然这不过重要了,后面提到的 同步 和 异步 才是比较重要的。
下面则是本文的重点,同步和异步网络IO的性能测试和差别对比。
[1] | 轻量级web server Tornado代码分析(http://blog.csdn.net/goldlevi/article/details/7047726) |
使用同步和异步的方式来写一段延时代码,而后再使用 apachebench进行压力测试:
因为本文只是作性能对比,而不是性能的上限对比,因此都使用的是比较少的压力。
class SyncSleepHandler(RequestHandler): """ 同步的方式,一个延时1s的接口 """ def get(self): time.sleep(1) self.write("when i sleep 5s") class SleepHandler(RequestHandler): """ 异步的延时1秒的接口 """ @tornado.gen.coroutine def get(self): yield tornado.gen.Task( tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 1 ) self.write("when i sleep 5s")
➜ / ab -n 200 -c 40 http://localhost:8009/demo/syncsleep-handler/ This is ApacheBench, Version 2.3 <$Revision: 1528965 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 100 requests Completed 200 requests Finished 200 requests Server Software: TornadoServer/4.2.1 Server Hostname: localhost Server Port: 8009 Document Path: /demo/syncsleep-handler/ Document Length: 15 bytes Concurrency Level: 40 Time taken for tests: 200.746 seconds Complete requests: 200 Failed requests: 0 Total transferred: 42000 bytes HTML transferred: 3000 bytes Requests per second: 1.00 [#/sec] (mean) Time per request: 40149.159 [ms] (mean) Time per request: 1003.729 [ms] (mean, across all concurrent requests) Transfer rate: 0.20 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 1 Processing: 1005 36235 18692.2 38133 200745 Waiting: 1005 36234 18692.2 38133 200745 Total: 1006 36235 18692.2 38133 200746 Percentage of the requests served within a certain time (ms) 50% 38133 66% 38137 75% 38142 80% 38161 90% 38171 95% 38176 98% 38179 99% 199742 100% 200746 (longest request)
➜ / ab -n 200 -c 40 http://localhost:8009/demo/sleep-handler/ This is ApacheBench, Version 2.3 <$Revision: 1528965 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 100 requests Completed 200 requests Finished 200 requests Server Software: TornadoServer/4.2.1 Server Hostname: localhost Server Port: 8009 Document Path: /demo/sleep-handler/ Document Length: 15 bytes Concurrency Level: 40 Time taken for tests: 5.083 seconds Complete requests: 200 Failed requests: 0 Total transferred: 42000 bytes HTML transferred: 3000 bytes Requests per second: 39.35 [#/sec] (mean) Time per request: 1016.611 [ms] (mean) Time per request: 25.415 [ms] (mean, across all concurrent requests) Transfer rate: 8.07 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.4 0 2 Processing: 1001 1010 12.0 1005 1053 Waiting: 1001 1010 12.0 1005 1053 Total: 1001 1010 12.3 1005 1055 Percentage of the requests served within a certain time (ms) 50% 1005 66% 1009 75% 1011 80% 1015 90% 1032 95% 1044 98% 1045 99% 1054 100% 1055 (longest request)
在并发量为40,总请求量为200的简单的压力测试里面,两种网络IO模型的编程方式的性能对好比下:
性能指标 | 同步阻塞式 | 异步非阻塞式 |
---|---|---|
每秒处理请求数(Requests per second) | 1 | 39 |
请求平均等待时间-ms(Time per request,mean) | 40149 | 1017 |
请求平均处理时间-ms(Time per request,across all ) | 1003 | 25 |
测试的结果比较符合被测试程序的理论预期,由于被测试程序就功能就是:一个1s的延时等待。
显然:异步非阻塞式 和性能是远高于 同步阻塞式 的。
在上表中的 同步IO模型 数据里:只要是进入了单个请求的处理环节,进入到睡眠等待的 内核态 操做时,就会将整个进程给 阻塞,别的程序就只能进入 等待 状态了,这样本质上仍是使用的 串行 的处理方式,因此 请求平均处理时间 大概是1000ms(1秒)左右,而后完成一个并发度为40的请求平均等待时间为40149ms。
关于上面参数的理解能够进行简单的类比解释。
以以下场景为例子:客户去银行处理业务的窗口办理业务。
对应CPU,窗口数对应着核心数,即真正的实现并行的能力,即不是在时间分片后交错进行的 “假象并行”
对应着单次的并发度,即本次做业须要处理的任务量
总请求量:从银行大厅外面陆续过来加入到大厅队伍的客户的累计人数
内核态操做:银行业务中必须只能由前台服务员处理的操做
用户态操做:客户本身要处理的工做,好比:准备好本身的身份证,到外面复印证件,打电话和公司同事确认信息等等。
那么关于 同步 和 异步 的概念类好比下:
在这个假设的场景里面,不论是同步仍是异步,业务员(CPU)都是 满负荷 的工做,可是却极大的节省了客户(web服务器进程) 的时间。这样客户自身能够把等待业务员响应的时间都利用起来作一些其它工做,这样就极大地提升了总体的工做效率。
众所周知,python有GIL,因此多线程实际上是伪多线程。tornado因而就单进程只用单线程,不作线程切换,可是又要实现并行的方式,就所有使用异步了。只要是某个请求进入了内核态的耗时的IO操做,tornado的主进程在发起内核IO初始化以后就作无论它了,马上回到web的监控中来去响应别的请求。等内核态的IO完成以后,再回调到用户态的主进程处理结果。若是是用同步模型,若是是使用单进程多线程,则会形成线程切换的开销,若是使用单进程单线程(像django同样),若是有一个请求比较耗时,第二我的的请求只会排队等候的,Web服务进程绝大多数状况都是被阻塞状态,性能就极大地下降了。
最后结合前面的延时1s的例子,再加一个即时响应的接口示例:
class JustNowHandler(tornado.web.RequestHandler): def get(self): self.write("i hope just now see you")
有兴趣的同窗能够本身作实验。 事先约定:
使用单核模式运行web服务器。
而后在浏览器中以不一样的顺序组合运行程序请求接口:
同步模型中,一旦进程被阻塞掉,那么程序的效率就被等待的时间给严重下降了。
有兴趣的同窗,能够更深刻的研究一下 《Unix网络编程-卷1,套接字联网API》(W.Richard Stevens) 的第6章第2节 I/O模型。
在python的web框架里面,tornado就是采用的最高效的异步非阻塞框架,能够在python语言下提供高性能的web应用服务。
做者: | Harmo哈莫 |
---|---|
做者介绍: | https://zhengwh.github.io |
技术博客: | http://www.cnblogs.com/beer |
Email: | dreamzsm@gmail.com |
QQ: | 1295351490 |
时间: | 2015-10 |
版权声明: | 欢迎以学习交流为目的读者随意转载,可是请 【注明出处】 |
支持本文: | 若是文章对您有启发,能够点击博客右下角的按钮进行 【推荐】 |