Skip to content

Instantly share code, notes, and snippets.

@KaiserWerk
Created August 21, 2022 23:19
Show Gist options
  • Save KaiserWerk/2b11ab8e0e2c58f517ed003df4ab889c to your computer and use it in GitHub Desktop.
Save KaiserWerk/2b11ab8e0e2c58f517ed003df4ab889c to your computer and use it in GitHub Desktop.
Golang benchmark testing different HTTP router implementations

Please observe the difference in speed when calling resp.Body.Close().

package router
import "net/http"
type Router struct {
routes map[string]http.HandlerFunc
}
func NewRouter() *Router {
return &Router{
routes: make(map[string]http.HandlerFunc),
}
}
func (router *Router) HandleFunc(p string, f http.HandlerFunc) {
router.routes[p] = f
}
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if hf, found := router.routes[path]; found {
hf.ServeHTTP(w, r)
} else {
http.Error(w, "failed to match route", http.StatusNotFound)
}
}
package router
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/mux"
"github.com/julienschmidt/httprouter"
)
func Benchmark_SuperSimpleRouter(b *testing.B) {
router := NewRouter()
router.HandleFunc("/test", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "Hello World")
})
srv := httptest.NewServer(router)
defer srv.Close()
cl := srv.Client()
b.ResetTimer()
for i := 0; i < b.N; i++ {
req, _ := http.NewRequest(http.MethodGet, srv.URL+"/test", nil)
resp, err := cl.Do(req)
if err != nil {
b.Fatalf("failed to execute request: %s", err.Error())
}
resp.Body.Close()
if resp.StatusCode != 200 {
b.Fatalf("expected status code 200, got %d", resp.StatusCode)
}
}
}
func Benchmark_HTTPServeMux(b *testing.B) {
router := http.NewServeMux()
router.HandleFunc("/test", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "Hello World")
})
srv := httptest.NewServer(router)
defer srv.Close()
cl := srv.Client()
b.ResetTimer()
for i := 0; i < b.N; i++ {
req, _ := http.NewRequest(http.MethodGet, srv.URL+"/test", nil)
resp, err := cl.Do(req)
if err != nil {
b.Fatalf("failed to execute request: %s", err.Error())
}
resp.Body.Close()
if resp.StatusCode != 200 {
b.Fatalf("expected status code 200, got %d", resp.StatusCode)
}
}
}
func Benchmark_GorillaMux(b *testing.B) {
router := mux.NewRouter()
router.HandleFunc("/test", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "Hello World")
})
srv := httptest.NewServer(router)
defer srv.Close()
cl := srv.Client()
b.ResetTimer()
for i := 0; i < b.N; i++ {
req, _ := http.NewRequest(http.MethodGet, srv.URL+"/test", nil)
_, err := cl.Do(req)
if err != nil {
b.Fatalf("failed to execute request: %s", err.Error())
}
}
}
func Benchmark_JSHTTPRouter(b *testing.B) {
router := httprouter.New()
router.HandlerFunc(http.MethodGet, "/test", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "Hello World")
})
srv := httptest.NewServer(router)
defer srv.Close()
cl := srv.Client()
b.ResetTimer()
for i := 0; i < b.N; i++ {
req, _ := http.NewRequest(http.MethodGet, srv.URL+"/test", nil)
_, err := cl.Do(req)
if err != nil {
b.Fatalf("failed to execute request: %s", err.Error())
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment