V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
KaSunMt
V2EX  ›  问与答

Go Best Practices 之 B 站源码分析

  •  1
     
  •   KaSunMt · 2019-04-22 23:35:03 +08:00 · 1711 次点击
    这是一个创建于 2343 天前的主题,其中的信息可能已经有所发展或是发生改变。

    过度加锁

    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 的写法最好避免)。

    json.Encoder & sync.Pool

    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 和数据拷贝操作。

    context.WithTimeout

    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

    这是 Go,不是 C,不要省那么点空间

    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的代码,欢迎大家继续补充。

    目前尚无回复
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2644 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 14:42 · PVG 22:42 · LAX 07:42 · JFK 10:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.