標籤:html imp 體驗 思考 ons 調度 個數 進程 方便
最近學習Golang,總想體驗下並發到底有多叼,必我大 python強勢多少。 學習了官方教程的http 服務,用效能測試工具wrk測試了下,發現結果很令人驚訝~
wrk可以參考我的部落格,有基本用法說明:http://blog.yuanzhaoyi.cn/2018/01/12/test.html
測試命令:wrk -t10 -d1m -c200 http://127.0.0.1:8080
含義:10線程,並發200連結,持續1分鐘
http服務均返回基本的: "Hello World",應該不會有IO阻塞
Python 標準庫BaseHTTPRequestHandler實現:
from http.server import BaseHTTPRequestHandlerfrom urllib import parseclass GetHandler(BaseHTTPRequestHandler): def do_GET(self): message = "Hello World" self.send_response(200) self.end_headers() self.wfile.write(message.encode(‘utf-8‘))if __name__ == ‘__main__‘: from http.server import HTTPServer server = HTTPServer((‘localhost‘, 8080), GetHandler) print(‘Starting server, use <Ctrl-C> to stop‘) server.serve_forever()
結果:每秒響應數量只有282個,測試時間越長會越低
因為是但進程,單線程,這個資料應該不錯了,雖然GIL在io阻塞會釋放線程,但也有一點效能消耗
Running 1m test @ http://127.0.0.1:8080 10 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.05ms 6.73ms 265.58ms 98.90% Req/Sec 107.11 103.19 1.05k 84.08% 16959 requests in 1.00m, 1.65MB read Socket errors: connect 0, read 19024, write 59, timeout 0Requests/sec: 282.21Transfer/sec: 28.11KB
非同步架構為了方便,我們先用基於twisted的事件迴圈的tornado:
import tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world")if __name__ == "__main__": application = tornado.web.Application([ (r"/", MainHandler), ]) application.listen(8080) tornado.ioloop.IOLoop.current().start()
結果:每秒響應數量有1300多個,明顯好很多
Running 1m test @ http://127.0.0.1:8080 10 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 147.44ms 45.17ms 467.54ms 86.25% Req/Sec 141.40 57.52 202.00 65.17% 81818 requests in 1.00m, 16.15MB read Socket errors: connect 0, read 1, write 0, timeout 0Requests/sec: 1361.25Transfer/sec: 275.17KB
Python3開始支援原生的協程來處理事件迴圈,雖然tornado也支援,但為了方便,直接用號稱最快的sanic測試吧
from sanic import Sanicfrom sanic.response import jsonapp = Sanic()@app.route("/")async def test(request): return json({"hello": "world"})if __name__ == "__main__": app.run(host="0.0.0.0", debug=False, port=8080)
結果:每秒響應數量達到4400多了,看起來很不錯了
Running 1m test @ http://127.0.0.1:8080 10 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 45.59ms 16.91ms 255.88ms 71.70% Req/Sec 443.64 111.85 0.89k 68.56% 264956 requests in 1.00m, 32.09MB read Socket errors: connect 0, read 67, write 0, timeout 0Requests/sec: 4408.87Transfer/sec: 546.80KB
最近學習了GoLang,就基於官方指南的http服務進行了基本測試:
package mainimport ( "fmt" "log" "net/http")type Hello struct{}func (h Hello) ServeHTTP( w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello World!")}func main() { h := Hello{} err := http.ListenAndServe("localhost:8080", h) if err != nil { log.Fatal(err) }}
結果也是讓我大開眼界:每秒響應數量達到了35365,和python服務都不是一個量級
Running 1m test @ http://127.0.0.1:8080 10 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 7.26ms 9.46ms 210.93ms 93.36% Req/Sec 3.56k 1.10k 19.98k 74.96% 2125366 requests in 1.00m, 261.47MB readRequests/sec: 35365.98Transfer/sec: 4.35MB
簡單總結下,測試中,記憶體都沒有明顯增長,必定沒有什麼操作,僅僅返回一個字串。但是GoLang的CPU使用率明顯增長,Sanic服務也有差不多的增長,其餘CPU使用率增長幅度不大,但Python的服務應該都只用了CPU都一核心。但當CPU佔比差不多的時候,GoLang的響應能力明顯要更勝一籌。具體原因思考,除了CPU的核心使用區別之外,即真正並行的實現外,好像也沒什麼了。Python的非同步服務和GoLang的服務應該都基於事件迴圈實現了協程的調度,當然實現方法肯定有很大的不同,具體還要繼續學習了。不過GoLang天生並發的支援,的確對此最佳化的很不錯。
這幾個測試都是基於好奇,比較簡單也不夠嚴謹,但我覺得可以說明一些區別。如果發現什麼問題,歡迎留言。
基本http服務效能測試(Python vs Golang)