我尝试比较了Go语言的web框架Echo和Python的web框架Flask的速度
我們來比較一下 Golang 的 Echo 和 Python 的 Flask 的執行速度。
我之前一直在使用Python,没有特别的不满意,但最近开始学习使用Golang。尽管Python在开发一些小型项目上很方便,但当需要速度时,我想用Golang来感受一下它能有多快。所以我决定比较Golang中代表性的web框架Echo和Python中的轻量级web框架Flask,看看它们在速度上有多大的差异。
考试环境
在VMware上建立的Ubuntu 16.04是使用普通硬盘而非SSD。
配置为i7处理器,内存6GB。
安装了Python 2.7和Go语言1.6。
返回一个简单的字符串的Web应用程序
为了掌握直观感受,首先制作一个简单的网络应用程序。
使用Golang的Echo库创建一个简单的应用程序。
首先,从一个使用Go语言创建的简单Web应用开始。
package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Run(standard.New(":1323"))
}
如果使用Golang的Echo库,只需写入以下内容,就可以快速创建一个返回”Hello World”的web应用程序,非常方便。
试着测量golang-echo的速度。
用Apache Bench工具来测试速度
shibacow@ubuntu:~/prog/golang/echo_test$ ab -n 100000 -c 100 http://localhost:1323/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
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 10000 requests
...
Completed 100000 requests
Finished 100000 requests
Server Software:
Server Hostname: localhost
Server Port: 1323
Document Path: /
Document Length: 13 bytes
Concurrency Level: 100
Time taken for tests: 9.525 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 13000000 bytes
HTML transferred: 1300000 bytes
Requests per second: 10498.93 [#/sec] (mean)
Time per request: 9.525 [ms] (mean)
Time per request: 0.095 [ms] (mean, across all concurrent requests)
Transfer rate: 1332.87 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 3 2.8 2 19
Processing: 0 6 3.2 7 31
Waiting: 0 5 2.5 4 26
Total: 0 9 4.1 9 33
Percentage of the requests served within a certain time (ms)
50% 9
66% 11
75% 12
80% 13
90% 15
95% 17
98% 18
99% 19
100% 33 (longest request)
每秒请求次数:10498.93次/秒
不需要进行调整,似乎可以达到每秒1万个请求。
使用Python-Flask创建的简单应用程序。
下一步,我尝试研究一下Flask。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run()
使用 Flask 搭建一个简单的网页应用,并返回一个”Hello World”的字符串。
Python-Flask的性能测试
shibacow@ubuntu:~/prog/golang/echo_test$ ab -n 10000 -c 100 http://localhost:5000/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
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 1000 requests
...
Completed 10000 requests
Finished 10000 requests
Server Software: Werkzeug/0.11.10
Server Hostname: localhost
Server Port: 5000
Document Path: /
Document Length: 12 bytes
Concurrency Level: 100
Time taken for tests: 8.190 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1680000 bytes
HTML transferred: 120000 bytes
Requests per second: 1220.97 [#/sec] (mean)
Time per request: 81.902 [ms] (mean)
Time per request: 0.819 [ms] (mean, across all concurrent requests)
Transfer rate: 200.32 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.7 0 8
Processing: 2 81 12.6 81 148
Waiting: 1 81 12.5 81 148
Total: 6 81 12.2 81 148
Percentage of the requests served within a certain time (ms)
50% 81
66% 90
75% 91
80% 92
90% 95
95% 98
98% 101
99% 106
100% 148 (longest request)
每秒请求次数:1220.97 次/秒
不做任何特别处理, 大约能达到1220req/sec。
连接到Mongo并搜索并返回结果的Web应用程序。
因为简单的应用程序与现实问题存在不一致,所以连接到mongo并进行搜索以返回结果,加入了一些超出现实的元素。
参考了该网站。
使用golang-echo连接到mongo的网络应用程序
package main
import (
// サーバ系
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
// mongo系
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
// 型
"strconv"
//"reflect"
)
// ユーザクラス
type User struct {
Name string `bson:"name"`
Id int `bson:"id"`
}
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
// :id, :name に値が入っていないとNot Foundになる
e.GET("/users/id/:id", func(c echo.Context) error {
// 数値に変換する必要あり
var id int
id, _ = strconv.Atoi(c.Param("id"))
//idでDBを引く
session, _ := mgo.Dial("mongodb://localhost")
defer session.Close()
db := session.DB("test")
// id指定でユーザ取得
var results []User
fmt.Println(id)
db.C("user").Find(bson.M{"id": id}).All(&results)
fmt.Println("Results of one user: ", results)
fmt.Println(len(results))
if len(results) == 0 {
return c.String(http.StatusOK, "No user")
}else{
name := results[0].Name
return c.String(http.StatusOK, "Hello, " + name)
}
})
e.POST("/user", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, POST user")
})
// ポート
e.Run(standard.New(":1323"))
}
Golang-Echo和Mongo连接的基准测试
与Mongo建立连接并返回结果的基准测试。
shibacow@ubuntu:~/prog/golang/echo_test$ ab -n 10000 -c 100 http://localhost:1323/users/id/1
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
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 1000 requests
.....
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: localhost
Server Port: 1323
Document Path: /users/id/1
Document Length: 11 bytes
Concurrency Level: 100
Time taken for tests: 9.156 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1280000 bytes
HTML transferred: 110000 bytes
Requests per second: 1092.21 [#/sec] (mean)
Time per request: 91.557 [ms] (mean)
Time per request: 0.916 [ms] (mean, across all concurrent requests)
Transfer rate: 136.53 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 4.4 0 29
Processing: 9 90 24.9 88 213
Waiting: 9 89 25.1 87 213
Total: 25 91 24.3 89 213
Percentage of the requests served within a certain time (ms)
50% 89
66% 100
75% 107
80% 112
90% 123
95% 134
98% 147
99% 156
100% 213 (longest request)
每秒请求次数:1092.21次/秒
使用Python-Flask连接Mongo数据库并获取结果。
制作一个使用MongoDB进行连接的应用程序。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask
from flask_pymongo import PyMongo
app = Flask(__name__)
app.config['MONGO_HOST']='localhost'
app.config['MONGO_DBNAME'] = 'test'
mongo = PyMongo(app)
@app.route("/users/id/<int:id>")
def user_id(id):
user= mongo.db.user.find_one({"id":id})
msg="Hello id={} name={}".format(user["id"],user['name'])
return msg
@app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run(host="0.0.0.0",debug=False)
使用Python Flask进行基准测试。
shibacow@ubuntu:~/prog/python/flask_test$ ab -n 10000 -c100 http://localhost:500
0/users/id/1
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
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 1000 requests
.....
Completed 10000 requests
Finished 10000 requests
Server Software: Werkzeug/0.11.10
Server Hostname: localhost
Server Port: 5000
Document Path: /users/id/1
Document Length: 20 bytes
Concurrency Level: 100
Time taken for tests: 12.639 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1760000 bytes
HTML transferred: 200000 bytes
Requests per second: 791.22 [#/sec] (mean)
Time per request: 126.387 [ms] (mean)
Time per request: 1.264 [ms] (mean, across all concurrent requests)
Transfer rate: 135.99 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.7 0 8
Processing: 6 126 11.8 125 164
Waiting: 6 125 11.8 125 163
Total: 11 126 11.5 125 164
Percentage of the requests served within a certain time (ms)
50% 125
66% 129
75% 131
80% 132
90% 138
95% 143
98% 149
99% 153
100% 164 (longest request)
每秒请求数:791.22次/秒
整理一下
我比较了Golang的Echo和Python的Flask的速度。
在一个简单的应用程序中,性能差异大约是10倍,但是连接到Mongo时速度差异并不明显。每次请求都要连接到Mongo,所以可能负载更高。如果使用echo或pymongo连接池,结果可能会有所改变。我比较Golang和Python并不是想贬低Python的性能,只是想体验一下它们之间大致有多大差距。
总结(追加)
在下面的附注中提到,停止每次连接到Mongo数据库,而是连接一次并进行重用,可以大大提高速度。但是,由于会话保持状态,因此在使用时需要进行验证,以确定在更新或提交等操作时会发生什么,因此在生产环境中使用之前需要进行验证,而不仅仅依靠基准测试。
使用golang-echo连接mongo并提高获取结果的速度
改进 Golang-Echo 的 Mongo 连接。
在上面的例子中,每个请求都重复连接和断开与mongo数据库的连接。现在改为在GET请求的外部进行连接和断开操作。由于将输出切换到标准输出导致速度变慢,所以我们也取消了这一操作。
package main
import (
// サーバ系
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
// mongo系
//"fmt" //標準出力は遅いので、止める
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
// 型
"strconv"
//"reflect"
)
// ユーザクラス
type User struct {
Name string `bson:"name"`
Id int `bson:"id"`
}
func main() {
e := echo.New()
//idでDBを引くGETの外側に出して、毎回の接続・切断をやめた
session, _ := mgo.Dial("mongodb://localhost")
defer session.Close()
db := session.DB("test")
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
// :id, :name に値が入っていないとNot Foundになる
e.GET("/users/id/:id", func(c echo.Context) error {
// 数値に変換する必要あり
var id int
id, _ = strconv.Atoi(c.Param("id"))
// id指定でユーザ取得
var results []User
//fmt.Println(id)
db.C("user").Find(bson.M{"id": id}).All(&results)
//fmt.Println("Results of one user: ", results)
//fmt.Println(len(results))
if len(results) == 0 {
return c.String(http.StatusOK, "No user")
}else{
name := results[0].Name
return c.String(http.StatusOK, "Hello, " + name)
}
})
e.POST("/user", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, POST user")
})
// ポート
e.Run(standard.New(":1323"))
}
改良版基准测试
经过以上改进,速度显著提升,达到了6282次/秒。
shibacow@ubuntu:~$ ab -n 100000 -c 100 http://localhost:1323/users/id/1
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
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 10000 requests
....
Completed 100000 requests
Finished 100000 requests
Server Software:
Server Hostname: localhost
Server Port: 1323
Document Path: /users/id/1
Document Length: 11 bytes
Concurrency Level: 100
Time taken for tests: 15.914 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 12800000 bytes
HTML transferred: 1100000 bytes
Requests per second: 6283.74 [#/sec] (mean)
Time per request: 15.914 [ms] (mean)
Time per request: 0.159 [ms] (mean, across all concurrent requests)
Transfer rate: 785.47 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 3.2 3 21
Processing: 0 12 5.0 12 44
Waiting: 0 10 4.9 10 44
Total: 0 16 5.2 15 45
Percentage of the requests served within a certain time (ms)
50% 15
66% 17
75% 19
80% 20
90% 22
95% 25
98% 29
99% 32
100% 45 (longest request)
每秒请求数:6283.74个/秒
大大提速了。