Adds new context caching system

- Reduces allocation overhead
- Reduces Garbage Collection stress
- Reduces memory fragmentation
This commit is contained in:
Manu Mtz-Almeida 2014-07-02 20:17:57 +02:00
parent 503b1fadae
commit 10979dd862
1 changed files with 39 additions and 10 deletions

49
gin.go
View File

@ -56,9 +56,10 @@ type (
// Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares. // Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares.
Engine struct { Engine struct {
*RouterGroup *RouterGroup
HTMLTemplates *template.Template
cache chan *Context
handlers404 []HandlerFunc handlers404 []HandlerFunc
router *httprouter.Router router *httprouter.Router
HTMLTemplates *template.Template
} }
) )
@ -74,10 +75,18 @@ func (a ErrorMsgs) String() string {
// Returns a new blank Engine instance without any middleware attached. // Returns a new blank Engine instance without any middleware attached.
// The most basic configuration // The most basic configuration
func New() *Engine { func New() *Engine {
cacheSize := 1024
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, cacheSize)
// Fill it with empty contexts
for i := 0; i < cacheSize/2; i++ {
engine.cache <- &Context{engine: engine}
}
return engine return engine
} }
@ -107,6 +116,7 @@ func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
} }
c.Next() c.Next()
engine.reuseContext(c)
} }
// ServeFiles serves files from the given file system root. // ServeFiles serves files from the given file system root.
@ -136,14 +146,31 @@ func (engine *Engine) Run(addr string) {
/********** ROUTES GROUPING *********/ /********** ROUTES GROUPING *********/
/************************************/ /************************************/
func (group *RouterGroup) 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 {
return &Context{ select {
Writer: w, case c := <-engine.cache:
Req: req, c.Writer = w
index: -1, c.Req = req
engine: group.engine, c.Params = params
Params: params, c.handlers = handlers
handlers: handlers, c.index = -1
return c
default:
return &Context{
Writer: w,
Req: req,
Params: params,
handlers: handlers,
index: -1,
engine: engine,
}
}
}
func (engine *Engine) reuseContext(c *Context) {
select {
case engine.cache <- c:
default:
} }
} }
@ -178,7 +205,9 @@ func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
p = path.Join(group.prefix, p) p = path.Join(group.prefix, p)
handlers = group.combineHandlers(handlers) handlers = group.combineHandlers(handlers)
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) {
group.createContext(w, req, params, handlers).Next() c := group.engine.createContext(w, req, params, handlers)
c.Next()
group.engine.reuseContext(c)
}) })
} }