1. 程式人生 > >基本http服務性能測試(Python vs Golang)

基本http服務性能測試(Python vs Golang)

utf als net send 強勢 max tps top nco

最近學習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 BaseHTTPRequestHandler
from urllib import parse class 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 0 Requests/sec: 282.21 Transfer/sec: 28.11KB

異步框架為了方便,我們先用基於twisted的事件循環的tornado:

import tornado.ioloop
import tornado.web

class 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 0
Requests/sec:   1361.25
Transfer/sec:    275.17KB

Python3開始支持原生的協程來處理事件循環,雖然tornado也支持,但為了方便,直接用號稱最快的sanic測試吧

from sanic import Sanic
from sanic.response import json

app = 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 0
Requests/sec:   4408.87
Transfer/sec:    546.80KB

最近學習了GoLang,就基於官方指南的http服務進行了基本測試:

package main

import (
    "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 read
Requests/sec:  35365.98
Transfer/sec:      4.35MB

簡單總結下,測試中,內存都沒有明顯增長,必定沒有什麽操作,僅僅返回一個字符串。但是GoLang的CPU使用率明顯增長,Sanic服務也有差不多的增長,其余CPU使用率增長幅度不大,但Python的服務應該都只用了CPU都一核心。但當CPU占比差不多的時候,GoLang的響應能力明顯要更勝一籌。具體原因思考,除了CPU的核心使用區別之外,即真正並行的實現外,好像也沒什麽了。Python的異步服務和GoLang的服務應該都基於事件循環實現了協程的調度,當然實現方法肯定有很大的不同,具體還要繼續學習了。不過GoLang天生並發的支持,的確對此優化的很不錯。

這幾個測試都是基於好奇,比較簡單也不夠嚴謹,但我覺得可以說明一些區別。如果發現什麽問題,歡迎留言。

基本http服務性能測試(Python vs Golang)