Using sync.Pool instead of a channel

This commit is contained in:
Manu Mtz-Almeida 2014-07-06 21:09:23 +02:00
parent 31417dbc63
commit 3e4033673e
2 changed files with 18 additions and 65 deletions

66
gin.go
View File

@ -13,6 +13,7 @@ import (
"math" "math"
"net/http" "net/http"
"path" "path"
"sync"
) )
const ( const (
@ -37,11 +38,6 @@ type (
ErrorMsgs []ErrorMsg ErrorMsgs []ErrorMsg
Config struct {
CacheSize int
Preallocated int
}
// Context is the most important part of gin. It allows us to pass variables between middleware, // Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example. // manage the flow, validate the JSON of a request and render a JSON response for example.
Context struct { Context struct {
@ -68,19 +64,12 @@ type (
Engine struct { Engine struct {
*RouterGroup *RouterGroup
HTMLTemplates *template.Template HTMLTemplates *template.Template
cache chan *Context cache sync.Pool
handlers404 []HandlerFunc handlers404 []HandlerFunc
router *httprouter.Router router *httprouter.Router
} }
) )
var (
DefaultConfig = Config{
CacheSize: 1024,
Preallocated: 512,
}
)
// Allows type H to be used with xml.Marshal // Allows type H to be used with xml.Marshal
func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Name = xml.Name{"", "map"} start.Name = xml.Name{"", "map"}
@ -112,32 +101,19 @@ func (a ErrorMsgs) String() string {
return buffer.String() return buffer.String()
} }
func NewWithConfig(config Config) *Engine { // Returns a new blank Engine instance without any middleware attached.
if config.CacheSize < 2 { // The most basic configuration
panic("CacheSize must be at least 2") func New() *Engine {
}
if config.Preallocated > config.CacheSize {
panic("Preallocated must be less or equal to CacheSize")
}
engine := &Engine{} engine := &Engine{}
engine.RouterGroup = &RouterGroup{nil, "/", nil, engine} engine.RouterGroup = &RouterGroup{nil, "/", nil, engine}
engine.router = httprouter.New() engine.router = httprouter.New()
engine.router.NotFound = engine.handle404 engine.router.NotFound = engine.handle404
engine.cache = make(chan *Context, config.CacheSize) engine.cache.New = func() interface{} {
return &Context{Engine: engine, Writer: &responseWriter{}}
// Fill it with empty contexts
for i := 0; i < config.Preallocated; i++ {
engine.cache <- &Context{Engine: engine, Writer: &responseWriter{}}
} }
return engine return engine
} }
// Returns a new blank Engine instance without any middleware attached.
// The most basic configuration
func New() *Engine {
return NewWithConfig(DefaultConfig)
}
// Returns a Engine instance with the Logger and Recovery already attached. // Returns a Engine instance with the Logger and Recovery already attached.
func Default() *Engine { func Default() *Engine {
engine := New() engine := New()
@ -154,10 +130,6 @@ func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
engine.handlers404 = handlers engine.handlers404 = handlers
} }
func (engine *Engine) CacheStress() float32 {
return 1.0 - float32(len(engine.cache))/float32(cap(engine.cache))
}
func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) { func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
handlers := engine.combineHandlers(engine.handlers404) handlers := engine.combineHandlers(engine.handlers404)
c := engine.createContext(w, req, nil, handlers) c := engine.createContext(w, req, nil, handlers)
@ -166,7 +138,7 @@ func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
if !c.Writer.Written() { if !c.Writer.Written() {
c.Data(404, MIMEPlain, []byte("404 page not found")) c.Data(404, MIMEPlain, []byte("404 page not found"))
} }
engine.reuseContext(c) engine.cache.Put(c)
} }
// ServeHTTP makes the router implement the http.Handler interface. // ServeHTTP makes the router implement the http.Handler interface.
@ -185,8 +157,7 @@ func (engine *Engine) Run(addr string) {
/************************************/ /************************************/
func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context { func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
select { c := engine.cache.Get().(*Context)
case c := <-engine.cache:
c.Writer.reset(w) c.Writer.reset(w)
c.Req = req c.Req = req
c.Params = params c.Params = params
@ -194,23 +165,6 @@ func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, pa
c.Keys = nil c.Keys = nil
c.index = -1 c.index = -1
return c return c
default:
return &Context{
Writer: &responseWriter{w, -1, false},
Req: req,
Params: params,
handlers: handlers,
index: -1,
Engine: engine,
}
}
}
func (engine *Engine) reuseContext(c *Context) {
select {
case engine.cache <- c:
default:
}
} }
// Adds middlewares to the group, see example code in github. // Adds middlewares to the group, see example code in github.
@ -246,7 +200,7 @@ func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
c := group.engine.createContext(w, req, params, handlers) c := group.engine.createContext(w, req, params, handlers)
c.Next() c.Next()
group.engine.reuseContext(c) group.engine.cache.Put(c)
}) })
} }

View File

@ -61,11 +61,10 @@ func Logger() HandlerFunc {
color = red color = red
} }
latency := time.Since(start) latency := time.Since(start)
stdlogger.Printf("[GIN] %v |%s %3d %s| %12v | %3.1f%% | %s %4s %s\n", stdlogger.Printf("[GIN] %v |%s %3d %s| %12v | %s %4s %s\n",
time.Now().Format("2006/01/02 - 15:04:05"), time.Now().Format("2006/01/02 - 15:04:05"),
color, c.Writer.Status(), reset, color, c.Writer.Status(), reset,
latency, latency,
c.Engine.CacheStress()*100,
requester, requester,
c.Req.Method, c.Req.URL.Path, c.Req.Method, c.Req.URL.Path,
) )