Go Web Frameworks 比較

  • 261
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Go言語にはいろいろなWebフレームワークが存在して、はっきりとしたデファクトスタンダードが決まっていません。

しいて言えば標準パッケージの net/http がデファクトですが、世の中ではそこに機能不足を感じた人たちが多くのフレームワークを開発しています。

そこで、いくつかのフレームワークを取り上げて、簡単なベンチマークと、それぞれのフレームワークでのいわゆるHello Worldの書き方をまとめておきます。

これによって、フレームワーク選びの参考になればと思います。

対象

Revel、Beego、Kochaなど、見かけたが入れていないものがいくつかあります。コマンドでスケルトンを作るもの、net/http の Handler interface を満たさないものは除外しました。

追加してくれる方はコメントか編集リクエストをお願いします!

Negroni あたりは入れたいですね。

個人的な感想

後半を読み飛ばしたい人のために、個人的な好みでオススメをあげておきますと、GinかEchoです。パフォーマンスも良く、いろいろ便利メソッドもあるのでよさそうです。

もっと薄いものが欲しい人は net/http が良いでしょう。

ベンチマーク

GET /gopher のリクエストを送って Hello, gopher! を返す単純なコードを書いて計測します。

ベンチマークは https://github.com/najeira/go-frameworks-benchmark にあります。フレームワークを追加したい方、ベンチマークの種類を増やしたい方、ぜひ Pull Request をお願いいたします。

なお、大量のハンドラがある場合のルーティングについて知りたい人は https://github.com/julienschmidt/go-http-routing-benchmark も参照してください。

時間

ns/op
Gin 734
Echo 879
Kami 1237
Goji 1299
Bone 1463
http 1854
Gocraft 1915
Gorilla 3944
Martini 5823

GinとEchoが優秀です。Martiniは内部でリフレクションを使っているためか遅いですが、それでもナノ秒の単位ですので、ここがアプリケーションのボトルネックになることはなさそうです。

allocs

allocs/op
Gin 3
Echo 5
Goji 6
Bone 7
http 7
Kami 9
Gocraft 12
Gorilla 15
Martini 22

ここでもGinとEchoが優秀です。とはいえ、GoのGCは進歩して性能が上がっていること、アプリケーション内でのアロケーションが支配的になるでしょうから、ここも大きな差はないといってよいでしょう。

GitHub

Stars Contributors
Martini 7995 93
Gin 4857 64
Goji 2888 17
Echo 2698 28
Gorilla 1808 27
Gocraft 918 11
Bone 823 11
Kami 127 4

Martiniは歴史もあり、初期に多くのStarsを獲得、またContributeも多いようです。次いでGin。また、Echoは2015年スタートですが、かなりの勢いでStarsを獲得しています。

コード

コード全体は https://github.com/najeira/go-frameworks-benchmark を見てください。ここでは雰囲気を把握してもらえれば。

Bone

m := bone.New()
m.Get("/:name", handler)
func handler(w http.ResponseWriter, r *http.Request) {
  name := bone.GetValue(r, "name")
  fmt.Fprintf(w, "Hello, %s", name)
}

Echo

m := echo.New()
m.Get("/:name", handler)
func handler(c *echo.Context) error {
  name := c.Param("name")
  return c.String(200, "Hello, %s", name)
}

Gin

m := gin.New()
m.GET("/:name", handler)
func handler(c *gin.Context) {
  name := c.Param("name")
  c.String(200, "Hello, %s", name)
}

Goji

m := goji.New()
m.Get("/:name", handler)
func handler(c goji.C, w http.ResponseWriter, r *http.Request) {
  name := c.URLParams["name"]
  fmt.Fprintf(w, "Hello, %s", name)
}

Gocraft

m := gocraft.New(ctx{})
m.Get("/:name", (*ctx).handler)
func (c *ctx) handler(w gocraft.ResponseWriter, r *gocraft.Request) {
  name := r.PathParams["name"]
  fmt.Fprintf(w, "Hello, %s", name)
}

Gorilla

m := goriila.NewRouter()
m.HandlerFunc("/{name}", handler)
func handler(w http.ResponseWriter, r *http.Request) {
  name := gorilla.Vars(r)["name"]
  fmt.Fprintf(w, "Hello, %s", name)
}

Kami

m := kami.New()
m.Get("/:name", handler)
func handler(c context.Context, w http.ResponseWriter, r *http.Request) {
  name := kami.Param(c, "name")
  fmt.Fprintf(w, "Hello, %s", name)
}

Martini

m := martini.Classic()
m.Get("/:name", handler)
func handler(w http.ResponseWriter, p *martini.Params) string {
  name := p["name"]
  return fmt.Sprintf("Hello, %s", name)
}