对共享数据的并发访问往往需要用到锁,而这是一个常见的性能瓶颈。而不可变数据共享式一种不需要用锁来保护共享数据的方式,创建后的数据永远不改变,这样就不会有竞争问题了。
// config.go
type Config struct {
LogLevel string
Timeout time.Duration
Features map[string]bool // 必须深拷贝,原始map的修改会影响已创建的配置
}
1
2
3
4
5
6
func NewConfig(logLevel string, timeout time.Duration, features map[string]bool) *Config {
copiedFeatures := make(map[string]bool, len(features))
for k, v := range features {
copiedFeatures[k] = v
}
return &Config{
LogLevel: logLevel,
Timeout: timeout,
Features: copiedFeatures,
}
}
1
2
3
4
5
6
7
8
9
10
11
12
var currentConfig atomic.Pointer[Config] // Go 1.19+ 特性
// LoadInitialConfig 初始化配置(必须保证线程安全)
func LoadInitialConfig() {
cfg := NewConfig("info", 5*time.Second, map[string]bool{"beta": true})
currentConfig.Store(cfg) // 原子存储初始配置
}
// GetConfig 安全获取当前配置(零锁消耗)
func GetConfig() *Config {
return currentConfig.Load() // 原子加载指针
}
1
2
3
4
5
6
7
8
9
10
11
12
func handler(w http.ResponseWriter, r *http.Request) {
cfg := GetConfig()
if cfg.Features["beta"] {
// Enable beta path
}
// Use cfg.Timeout, cfg.LogLevel, etc.
}
1
2
3
4
5
6
7
type Route struct {
Path string
Backend string
}
type RoutingTable struct {
Routes []Route
}
1
2
3
4
5
6
7
8
func NewRoutingTable(routes []Route) *RoutingTable {
copied := make([]Route, len(routes))
copy(copied, routes)
return &RoutingTable{Routes: copied}
}
1
2
3
4
5
var currentRoutes atomic.Pointer[RoutingTable]
func LoadInitialRoutes() {
table := NewRoutingTable([]Route{
{Path: "/api", Backend: "http://api.internal"},
{Path: "/admin", Backend: "http://admin.internal"},
})
currentRoutes.Store(table)
}
func GetRoutingTable() *RoutingTable {
return currentRoutes.Load()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func routeRequest(path string) string {
table := GetRoutingTable()
for _, route := range table.Routes {
if strings.HasPrefix(path, route.Path) {
return route.Backend
}
}
return ""
}
1
2
3
4
5
6
7
8
9
应用场景
注意事项
对共享数据的并发访问往往需要用到锁,而这是一个常见的性能瓶颈。而不可变数据共享式一种不需要用锁来保护共享数据的方式,创建后的数据永远不改变,这样就不会有竞争问题了。
// config.go
type Config struct {
LogLevel string
Timeout time.Duration
Features map[string]bool // 必须深拷贝,原始map的修改会影响已创建的配置
}
1
2
3
4
5
6
func NewConfig(logLevel string, timeout time.Duration, features map[string]bool) *Config {
copiedFeatures := make(map[string]bool, len(features))
for k, v := range features {
copiedFeatures[k] = v
}
return &Config{
LogLevel: logLevel,
Timeout: timeout,
Features: copiedFeatures,
}
}
1
2
3
4
5
6
7
8
9
10
11
12
var currentConfig atomic.Pointer[Config] // Go 1.19+ 特性
// LoadInitialConfig 初始化配置(必须保证线程安全)
func LoadInitialConfig() {
cfg := NewConfig("info", 5*time.Second, map[string]bool{"beta": true})
currentConfig.Store(cfg) // 原子存储初始配置
}
// GetConfig 安全获取当前配置(零锁消耗)
func GetConfig() *Config {
return currentConfig.Load() // 原子加载指针
}
1
2
3
4
5
6
7
8
9
10
11
12
func handler(w http.ResponseWriter, r *http.Request) {
cfg := GetConfig()
if cfg.Features["beta"] {
// Enable beta path
}
// Use cfg.Timeout, cfg.LogLevel, etc.
}
1
2
3
4
5
6
7
type Route struct {
Path string
Backend string
}
type RoutingTable struct {
Routes []Route
}
1
2
3
4
5
6
7
8
func NewRoutingTable(routes []Route) *RoutingTable {
copied := make([]Route, len(routes))
copy(copied, routes)
return &RoutingTable{Routes: copied}
}
1
2
3
4
5
var currentRoutes atomic.Pointer[RoutingTable]
func LoadInitialRoutes() {
table := NewRoutingTable([]Route{
{Path: "/api", Backend: "http://api.internal"},
{Path: "/admin", Backend: "http://admin.internal"},
})
currentRoutes.Store(table)
}
func GetRoutingTable() *RoutingTable {
return currentRoutes.Load()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func routeRequest(path string) string {
table := GetRoutingTable()
for _, route := range table.Routes {
if strings.HasPrefix(path, route.Path) {
return route.Backend
}
}
return ""
}
1
2
3
4
5
6
7
8
9
应用场景
注意事项