Source: library/net/http/blademaster/{server,client}.go
Code Sample:
type Engine struct {
RouterGroup
lock sync.RWMutex
conf *ServerConfig
address string
mux *http.ServeMux // http mux router
server atomic.Value // store *http.Server
metastore map[string]map[string]interface{} // metastore is the path as key and the metadata of this path as value, it export via /metadata
pcLock sync.RWMutex
methodConfigs map[string]*MethodConfig
injections []injection
}
两个锁+一个 atomic,我很难猜测写这段代码的人当时在想什么。。。
Go 的并发模型是共享内存的,刚接触的新手都喜欢在每个可能需要加锁的地方加上锁。以上述代码为例,这是一个只需要初始化一次,也就是只需要写操作一次的配置文件。这种配置文件要么在cmd/main.go
调用一次( B 站就是这么做的),要么在init
里调用。init
是单线程的,自带依赖树检查,可以放心大胆地做任何操作(单个 package 多个 init 的写法最好避免)。
Code Sample:
func writeJSON(w http.ResponseWriter, obj interface{}) (err error) {
var jsonBytes []byte
writeContentType(w, jsonContentType)
// err = json.NewEncoder(w).Encode(obj)
if jsonBytes, err = json.Marshal(obj); err != nil {
err = errors.WithStack(err)
return
}
if _, err = w.Write(jsonBytes); err != nil {
err = errors.WithStack(err)
}
return
}
优化 JSON 序列化性能的常见操作,避免 GC 和数据拷贝操作。
Code Sample:
func (engine *Engine) handleContext(c *Context) {
// ...
// get derived timeout from http request header,
// compare with the engine configured,
// and use the minimum one
engine.lock.RLock()
tm := time.Duration(engine.conf.Timeout)
engine.lock.RUnlock()
// the method config is preferred
if pc := engine.methodConfig(c.Request.URL.Path); pc != nil {
tm = time.Duration(pc.Timeout)
}
if ctm := timeout(req); ctm > 0 && tm > ctm {
tm = ctm
}
md := metadata.MD{
metadata.Color: color(req),
metadata.RemoteIP: remoteIP(req),
metadata.RemotePort: remotePort(req),
metadata.Caller: caller(req),
metadata.Mirror: mirror(req),
}
ctx := metadata.NewContext(context.Background(), md)
if tm > 0 {
c.Context, cancel = context.WithTimeout(ctx, tm)
} else {
c.Context, cancel = context.WithCancel(ctx)
}
defer cancel()
c.Next()
}
你需要调用<-ctx.Done()
来判断 ctx 是不是已经结束了: https://golang.org/pkg/context/#example_WithTimeout
Code Sample:
const (
// PlatAndroid is int8 for android.
PlatAndroid = int8(0)
// PlatIPhone is int8 for iphone.
PlatIPhone = int8(1)
// PlatIPad is int8 for ipad.
PlatIPad = int8(2)
// PlatWPhone is int8 for wphone.
PlatWPhone = int8(3)
// PlatAndroidG is int8 for Android Global.
PlatAndroidG = int8(4)
// PlatIPhoneI is int8 for Iphone Global.
PlatIPhoneI = int8(5)
// PlatIPadI is int8 for IPAD Global.
PlatIPadI = int8(6)
// PlatAndroidTV is int8 for AndroidTV Global.
PlatAndroidTV = int8(7)
// PlatAndroidI is int8 for Android Global.
PlatAndroidI = int8(8)
// PlatAndroidB is int8 for Android Blue.
PlatAndroidB = int8(9)
// PlatIPhoneB is int8 for Ios Blue
PlatIPhoneB = int8(10)
// PlatBilistudio is int8 for bilistudio
PlatBilistudio = int8(11)
// PlatAndroidTVYST is int8 for AndroidTV_YST Global.
PlatAndroidTVYST = int8(12)
)
目前只看了library/net/blademaster
的代码,欢迎大家继续补充。