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 |
版權聲明: | 歡迎以學習交流爲目的讀者隨意轉載,可是請 【註明出處】 |
支持本文: | 若是文章對您有啓發,能夠點擊博客右下角的按鈕進行 【推薦】 |