2017-08-25 52 views
2

我有一个结构与许多领域(其中一些指针也是其他结构),这是不断更新在一个单独的goroutine。在提供页面时,可以从go的http模板访问相同的结构。如何使用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 
}() 

去-HTTP处理程序:

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"}} 

到目前为止一切正常,但我知道,没有任何同步就可能发生坏事。什么是正确处理这个问题的首选方法?

回答

2

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

要么使用互斥当共享结构读取/更新:

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() 

或者,如果模板执行需要很长的时间,它可能是protitable使shared结构的副本,并通过副本时,执行该模板,以便在模板执行过程中不会阻止对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) 
} 

如果模板只使用shared领域的一小部分,就足以只是使那些当然的副本。