我正在编写一些 Go 网络服务(也在 Go 中使用 http.ListenAndServe 实现网络服务器)。我有一个结构图,我想将其保存在内存中(数据大小约为 100Kb),以供不同的 HTTP 请求使用。
在 Go 中如何实现这一点?我正在考虑使用全局包变量或缓存系统(如 memcache/groupcache)。
我正在编写一些 Go 网络服务(也在 Go 中使用 http.ListenAndServe 实现网络服务器)。我有一个结构图,我想将其保存在内存中(数据大小约为 100Kb),以供不同的 HTTP 请求使用。
在 Go 中如何实现这一点?我正在考虑使用全局包变量或缓存系统(如 memcache/groupcache)。
除了您已经收到的答案之外,请考虑使用接收者柯里化方法值和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
}
其余的基本相同,除了不是直接通过接收者的字段访问数据,而是通过 getter 和 setter 访问它们。在读取大部分数据的网络服务器中,您可能需要一个 RWMutex,以便可以同时执行读取操作。第二种方法的另一个优点是您已经封装了数据,因此如果您的应用程序有这样的需求,您可以在将来添加对 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
}