2017-08-25 49 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領域的一小部分,就足以只是使那些當然的副本。