我正在編寫一些Go web服務(也使用http.ListenAndServe在Go中實現web服務器)。 我有一個結構圖,我想保留在內存中(大約100Kb的數據大小)以供不同的http請求使用。Golang:在下面的http請求中存儲/緩存要提供的值
哪種方法在Go中實現這一點最好? 根據您的經驗,使用全局包變量或緩存系統(如memcache/groupcache)會更好嗎?
我正在編寫一些Go web服務(也使用http.ListenAndServe在Go中實現web服務器)。 我有一個結構圖,我想保留在內存中(大約100Kb的數據大小)以供不同的http請求使用。Golang:在下面的http請求中存儲/緩存要提供的值
哪種方法在Go中實現這一點最好? 根據您的經驗,使用全局包變量或緩存系統(如memcache/groupcache)會更好嗎?
不要沉迷於不成熟的優化。定義Go封裝API來封裝數據,然後您可以隨時更改實現。例如,只是塗鴉,
package data
type Key struct {
// . . .
}
type Data struct {
// . . .
}
var dataMap map[Key]Data
func init() {
dataMap = make(map[Key]Data)
}
func GetData(key Key) (*Data, error) {
data := dataMap[key]
return &data, nil
}
仍然解決問題的簡單解決方案通常是正確的方法。在服務器本地緩存數據既簡單又有效,即使使用更豐富的系統,也可以在許多情況下完成。
舉個例子,上個月我放了一個快速入門(http://ubuntu-edge.info),由於圍繞衆籌活動傳播的消息花了一些負擔,而且Go進程大部分時間負載很低,在一臺小型EC2機器上。數據很簡單,只是緩存在內存中,從外部進程正在更新的數據庫每分鐘刷新一次。
當我自己做這件事時,我通常會看memcache(現在是groupcache),這意味着它將複製更多的功能。例如,當內存中保存的數據過多時,或者當丟失服務器時可能會影響整個系統的性能,因爲緩存的數據全部消失,或者因爲性能受到爭用的影響。
請注意,groupcache實際上是一個庫,所以您可以將它嵌入到服務器中,而不是將其作爲實際的外部系統。
除了您已收到的答案之外,還可以考慮使用接收方兼容method values和http.HandlerFunc。
如果你的數據是在過程開始之前被加載的數據,你可以像這樣的東西去:
type Common struct {
Data map[string]*Data
}
func NewCommon() (*Common, error) {
// load data
return c, err
}
func (c *Common) Root(w http.ResponseWriter, r *http.Request) {
// handler
}
func (c *Common) Page(w http.ResponseWriter, r *http.Request) {
// handler
}
func main() {
common, err := NewCommon()
if err != nil { ... }
http.HandleFunc("/", common.Root)
http.HandleFunc("/page", common.Page)
http.ListenAndServe(...)
}
如果所有Common
數據是隻讀這工作得很好。如果Common
數據讀/寫,那麼你會希望有更多的東西一樣:
type Common struct {
lock sync.RWMutex
data map[string]Data // Data should probably not have any reference fields
}
func (c *Common) Get(key string) (*Data, bool) {
c.lock.RLock()
defer c.lock.RUnlock()
d, ok := c.data[key]
return &d, ok
}
func (c *Common) Set(key string, d *Data) {
c.lock.Lock()
defer c.lock.Unlock()
c.data[key] = *d
}
,其餘基本上是一樣的,只不過不是通過接收器的領域直接訪問數據,你會訪問他們通過獲得者和制定者。在讀取大部分數據的網絡服務器中,您可能需要一個RWMutex,以便讀取可以同時執行。第二種方法的另一個優點是你已經封裝了數據,所以你可以添加透明的寫入和/或從memcache或groupcache中讀取,或者在將來如果你的應用程序增長了這樣的需求,就可以添加這種性質的東西。
我真的很喜歡將我的處理程序定義爲對象上的方法的一件事情,它可以使單元測試變得更容易:您可以輕鬆定義一個包含所需值和輸出的table driven test,而無需用全局變量來解決問題。
這種解決方案不適合垃圾收集器,也不適合加載 - 平衡HTTP服務器,因爲每個客戶端都會響應不同的客戶端請求上的不同數據。 –
peterSO,你親自使用哪種實現? –
過早優化和過早泛化都是不好的。 :) –
我可能是錯的,但由於數據將被持久保存在併發的請求中,所以任何對擁有它的全局變量的訪問都應該被互斥鎖保護。 – kostix