代码之家  ›  专栏  ›  技术社区  ›  Minis

如何使用Go http包提供共享结构?

  •  2
  • Minis  · 技术社区  · 7 年前

    我有一个包含许多字段的结构(其中一些字段也是指向其他结构的指针),这些字段在一个单独的goroutine中不断更新。从go访问相同的结构 http

    type SharedStruct struct {
         Description string
         Counter int
         Status_ *Status
         LastChecked time.Time
         //other fields
    } 
    var shared = &SharedStruct{}
    
    go func() {
        //..updates fields every 5 minutes
    }()
    

    func someHandler(w http.ResponseWriter, r *http.Request) {
       t.ExecuteTemplate(w, "page.html", shared)
    }
    

    page.html 模板:

    ...
    Status: {{.Status_.StatusCode}}
    Counter: {{.Counter}}
    Last checked: {{.LastChecked.Format "2006-02-01 15:04:05"}}
    

    到目前为止,一切都按预期进行,但我知道,如果没有任何同步,坏事情可能会发生。正确处理这个问题的首选方法是什么?

    1 回复  |  直到 7 年前
        1
  •  2
  •   icza    7 年前

    首选方式与任何其他情况相同。

    var shared = &SharedStruct{}
    var mux = &sync.RWMutex{}
    
    func someHandler(w http.ResponseWriter, r *http.Request) {
        mux.RLock()
        defer mux.RUnlock()
        t.ExecuteTemplate(w, "page.html", shared)
    }
    
    // Code that modifies shared:
    mux.Lock()
    shared.Counter++
    mux.Unlock()
    

    或者,如果模板执行需要很长时间,则可以制作 shared 在执行模板时构造并传递副本,以便在模板执行期间访问 共享 未被阻止。请注意,在制作副本时,您仍然必须使用互斥锁。此外,如果不仅指针而且指针值可能会更改,您还必须复制这些值:

    func someHandler(w http.ResponseWriter, r *http.Request) {
        mux.RLock()
        shared2 := &SharedStruct{}
        *shared2 = *shared
        shared2.Status_ = new(Status)
        *shared2.Status_ = *shared.Status_
        mux.RUnlock()
    
        t.ExecuteTemplate(w, "page.html", shared2)
    }
    

    共享