当前位置:网站首页>[golang] follow the object pool sync Pool

[golang] follow the object pool sync Pool

2022-06-23 20:05:00 DDGarfield

Learn some skills in the source code

1. from Run() Start

stay go Linguistic gin In the frame , adopt .Run() start-up web service . Let's look at the source code :

//gin.go
func (engine *Engine) Run(addr ...string) (err error) {
 defer func() { debugPrintError(err) }()

 address := resolveAddress(addr)
 debugPrint("Listening and serving HTTP on %s\n", address)
 err = http.ListenAndServe(address, engine)
 return
}

among ListenAndServe yes net/http The listening address and processor specified in the library

//net/http/server.go
func ListenAndServe(addr string, handler Handler) error {
 server := &Server{Addr: addr, Handler: handler}
 return server.ListenAndServe()
}

You can see gin What is called in the source code is engine *Engine As Handler Parameters , Continue to check Handler Source code :

type Handler interface {
 ServeHTTP(ResponseWriter, *Request)
}

indeed Handler It's an interface , Interface method :ServeHTTP(ResponseWriter, *Request)

that Engine It must have come true **ServeHTTP** Method

adopt VSCode Navigation , I did Engine The struct implements this method :

// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 c := engine.pool.Get().(*Context)
 c.writermem.reset(w)
 c.Request = req
 c.reset()

 engine.handleHTTPRequest(c)

 engine.pool.Put(c)
}

2.sync.Pool On stage

Let's look at the third line of code in the previous section :

c := engine.pool.Get().(*Context)
type Engine struct {
 //omit code
    pool             sync.Pool
}

among pool The fields are sync.Pool type , What is that sync.Pool?

original : This is a go The concept of a typical object pool in a language , In order to reduce the GC, Reduce the frequency of memory requests , Construct a pool of reusable objects ,engine.pool.Get() Is to take an object out of the pool , Cast to context The pointer .

  1. Through the object pool , Reduce the consumption of memory application and garbage collection for each temporary object creation
  2. Frequent object application and recycling , You can use object pooling to optimize your code
  3. It can avoid object reference or other interference , Without affecting the actual function of the code , After an object is removed from the pool , Then do initialization

3. Usage method

sync.Pool It's very simple to use :

3.1 Statement

//gin.go
func New() *Engine {
 debugPrintWARNINGNew()
 engine := &Engine{
  RouterGroup: RouterGroup{
   Handlers: nil,
   basePath: "/",
   root:     true,
  },
  FuncMap:                template.FuncMap{},
  RedirectTrailingSlash:  true,
  RedirectFixedPath:      false,
  HandleMethodNotAllowed: false,
  ForwardedByClientIP:    true,
  AppEngine:              defaultAppEngine,
  UseRawPath:             false,
  RemoveExtraSlash:       false,
  UnescapePathValues:     true,
  MaxMultipartMemory:     defaultMultipartMemory,
  trees:                  make(methodTrees, 0, 9),
  delims:                 render.Delims{Left: "{{", Right: "}}"},
  secureJsonPrefix:       "while(1);",
 }
 engine.RouterGroup.engine = engine
    // Realization New function 
 engine.pool.New = func() interface{} {
  return engine.allocateContext()
 }
 return engine
}
  • Just implement New Function . When there are no objects in the object pool , Will call New Function creation .

3.2 Get()

obtain

  • Get() Used to get objects from the object pool , Because the return value is interface{}, Therefore, type conversion is required , The above code has been shown .
c := engine.pool.Get().(*Context)

3.3 Put()

Put back

  • Put() After the object is used , Return object pool .

processed http After the request , Also put context Put back into the object pool :

engine.handleHTTPRequest(c)
engine.pool.Put(c)

3. matters needing attention

sync.Pool It's scalable , Concurrent security . Its size is limited only by the size of memory , It can be seen as a container for storing the values of reusable objects . It is designed to Store allocated but temporarily unused objects , When you need it, you can get it directly from pool To take . Values in any store can be deleted at any time without notice , It can be dynamically expanded under high load , When inactive, the object pool shrinks .

Because of the bold font above , So the object pool is more suitable for storing some temporary state independent data , Because the values stored in the object pool may be deleted during garbage collection .http Requested context Context is such a type .

4. Add another technique

stay gin The source code defines Engine There is a sentence at the bottom of the structure :

var _ IRouter = &Engine{}

An obscure anonymous variable : Anonymous variables don't take up memory space , Memory will not be allocated , What's the use of it ? It can't be that the author forgot , Such a famous open source library .

original go Languages often encounter a scenario , After writing a structure , This structure implements many interfaces , The problem is , After the code is complicated , Who can still remember which interface is implemented or not , What do I do ?

  • Manual inspection , Um. , It's a way ,
  • Ctrl+F comparison , Find the method receiver , Um. , It's also a way

however , A better way , It depends on the compiler :

Define an anonymous variable var _ Interface type = Structure type pointer , This is mainly to ensure that the structure does implement the interface , The purpose is to Expose the problem in the compilation phase , Many third-party libraries and standard libraries do this , Worth learning .

Reference link

https://www.cnblogs.com/sunsky303/p/9706210.html

https://geektutu.com/post/hpg-sync-pool.html

------------------- End -------------------

原网站

版权声明
本文为[DDGarfield]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/174/202206231941490932.html