• 基本http服务性能测试(Python vs Golang)


    最近学习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天生并发的支持,的确对此优化的很不错。

    这几个测试都是基于好奇,比较简单也不够严谨,但我觉得可以说明一些区别。如果发现什么问题,欢迎留言。

  • 相关阅读:
    14_最长公共前缀_字符串_简单
    5. 最长回文子串_字符串_中等
    187. 重复的DNA序列_字符串_中等
    lr_bn_batchsize_deformable convolution_Hard negative mining
    彻底搞懂HTTPs的加密原理
    20. 有效的括号_字符串_简单
    13_罗马数字转整数_字符串_简单
    202_快乐数_数组_简答
    组件
    World
  • 原文地址:https://www.cnblogs.com/yuanzhaoyi/p/8685535.html
Copyright © 2020-2023  润新知