最近一段时间学习了一下 Go 这门语言,其中提到最多的就是 GoLang 的高性能 & 高并发,所以本着没有对比就没有伤害的原则,我准备将其与另外两个我所掌握的语言(Python、Java)进行一个简单的性能对比。
测试环境
我的 MacBook Pro,12个逻辑CPU + 16G内存
测试工具
https://github.com/wg/wrk
wrk -t8 -c100 -d30s --latency http://www.baidu.com
模拟8线程、100个并发,持续30秒的性能测试
实现
以下程序完整源码已放在 GitHub:https://github.com/Panmax/web-benchmark
Python
框架:Flask
容器:Gunicorn
运行环境:Docker
核心代码:
1 2 3 4 5 6 7 8 9 10 11
| # -*- coding: utf-8 -*-
from flask import Flask app = Flask(__name__)
@app.route("/") def hello(): return "Hello Python!"
if __name__ == '__main__': app.run()
|
Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| FROM ubuntu:14.04
ADD sources.list /etc/apt/sources.list ADD pip.conf ~/.pip/pip.conf
# Update OS # RUN sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list RUN apt-get update RUN apt-get -y upgrade
# Install Python RUN apt-get install -y python-dev python-pip
# Add requirements.txt ADD requirements.txt /webapp/requirements.txt
# Install gunicorn Python web server RUN pip install gunicorn==19.6.0 # Install app requirements RUN pip install -r /webapp/requirements.txt
# Create app directory ADD . /webapp
# Set the default directory for our environment ENV HOME /webapp WORKDIR /webapp
# Expose port 5000 for gunicorn EXPOSE 5000
ENTRYPOINT ["gunicorn", "-w", "24", "wsgi:app", "-b", "0.0.0.0:5000", "-n", "docker-flask", "--timeout", "45", "--max-requests", "10000"]
|
这里设置 24 个 worker,因为我的机器有 12 个逻辑CPU
启动命令
1 2
| docker build -t panmax/docker-flask-benchmark . docker run -d --name docker-flask-benchmark --restart=always -p 8081:5000 panmax/docker-flask-benchmark
|
Java
框架:SpringBoot
容器采用 SpringBoot
的默认 tomcat
容器,不进行其他修改。
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.jpanj.benchmark;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication @RestController public class BenchmarkApplication {
public static void main(String[] args) { SpringApplication.run(BenchmarkApplication.class, args); }
@GetMapping public String hello() { return "Hello Java!"; }
}
|
配置文件
启动命令
1 2 3 4
| ./gradlew build -xtest cd build/libs
java -jar benchmark-0.0.1-SNAPSHOT.jar
|
GoLang
框架:Gin
不需要配置任何容器
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package main
import ( "github.com/gin-gonic/gin" "net/http" )
func main() { router := gin.Default() router.GET("", func(c *gin.Context) {
c.String(http.StatusOK, "Hello GoLang!") }) router.Run(":8083") }
|
启动命令
1 2
| go build . ./gin-benchmark
|
go build 可以直接编译出一个可以执行文件,这个二进制文件可以直接放在其他机器上无需安装任何环境就可以运行起来,甚至可以在 Mac 上编译 Linux / Windows 的可执行文件,在 Linux 上编译 Mac / Windows 的可执行文件,这个特性非常爽。
通过浏览器可以验证以上使用 3 种语言开发的简单 Web 程序已经启起来了:
接下来我们逐个进行性能测试:
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ➜ wrk -t8 -c100 -d30s --latency http://127.0.0.1:8081/ Running 30s test @ http://127.0.0.1:8081/ 8 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 21.45ms 12.75ms 237.13ms 85.43% Req/Sec 332.10 111.19 640.00 71.40% Latency Distribution 50% 19.20ms 75% 26.01ms 90% 33.23ms 99% 90.03ms 15917 requests in 30.08s, 2.63MB read Socket errors: connect 0, read 560, write 0, timeout 0 Requests/sec: 529.21 Transfer/sec: 89.41KB
|
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ➜ wrk -t8 -c100 -d30s --latency http://127.0.0.1:8082/ Running 30s test @ http://127.0.0.1:8082/ 8 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 8.22ms 26.99ms 438.58ms 93.31% Req/Sec 6.93k 3.00k 16.38k 50.11% Latency Distribution 50% 1.26ms 75% 2.09ms 90% 12.81ms 99% 132.29ms 1631200 requests in 30.06s, 194.75MB read Requests/sec: 54256.97 Transfer/sec: 6.48MB
|
GoLang
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ➜ wrk -t8 -c100 -d30s --latency http://127.0.0.1:8083/ Running 30s test @ http://127.0.0.1:8083/ 8 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.80ms 1.95ms 24.69ms 85.85% Req/Sec 8.68k 786.97 11.03k 65.72% Latency Distribution 50% 1.36ms 75% 2.68ms 90% 4.32ms 99% 8.42ms 2078830 requests in 30.10s, 257.73MB read Requests/sec: 69064.35 Transfer/sec: 8.56MB
|
可以看到,在每秒请求数量(Requests/sec),也就是并发能力方面,测试结果为:
- Python: 529.21
- Java: 54256.97
- GoLang: 69064.35
线程平均延迟(Thread Stats - Avg - Latency)的测试结果为:
- Python: 21.45ms
- Java: 8.22ms
- GoLang: 1.80ms
可以看出,Go 在性能方面甩出 Python 几十条街是没有问题的,比 Java 的性能确实也好很多。
最后说明一下,这个测试可能存在不严谨性,但是我所采用的部署方案是大部分公司或者程序员最常使用的方式,也能在一定程度上说明问题。