【问题标题】:How to implement a singleton如何实现单例
【发布时间】:2020-06-08 10:58:44
【问题描述】:

我想用 Go 实现一个单例。普通单例的区别在于实例是单例,在映射结构中具有不同的键。像这样的代码。我不确定演示代码是否存在任何数据竞争。

var instanceLock sync.Mutex
var instances map[string]string

func getDemoInstance(key string) string {
    if value, ok := instances[key]; ok {
        return value
    }
    instanceLock.Lock()
    defer instanceLock.Unlock()
    if value, ok := instances[key]; ok {
        return value
    } else {
        instances[key] = key + key
        return key + key
    }
}

【问题讨论】:

    标签: go singleton instance


    【解决方案1】:

    是的,存在数据竞争,您可以通过go run -race main.go 运行它来确认。如果一个 goroutine 锁定并修改了 map,那么另一个 goroutine 可能会在锁定之前读取它。

    你可以使用sync.RWMutex在只读的时候读锁(允许多个读者互不阻塞)。

    例如:

    var (
        instancesMU sync.RWMutex
        instances   = map[string]string{}
    )
    
    func getDemoInstance(key string) string {
        instancesMU.RLock()
        if value, ok := instances[key]; ok {
            instancesMU.RUnlock()
            return value
        }
    
        instancesMU.RUnlock()
    
        instancesMU.Lock()
        defer instancesMU.Unlock()
        if value, ok := instances[key]; ok {
            return value
        }
        value := key + key
        instances[key] = value
        return value
    }
    

    【讨论】:

    • 对每个get操作使用sync.RWMutex会增加额外的性能成本,我只需要保证每个map key最多创建一个实例。有更好的解决方案吗?谢谢
    • @xiaoxu 是的,没错。而且,如果您不使用同步,您的应用程序将变得不可预测。数据竞争是未定义的行为。无法保证您的应用程序将正常运行。你选择:你想要一个正常运行的应用程序稍微慢一点,还是一个“更快”的、不正确的应用程序,它可能随时爆炸。
    • 是否有另一种更好的解决方案来保证每个映射键最多创建一个实例。
    • @xiaoxu 如果你想让它从多个goroutine并发访问,需要同步。
    【解决方案2】:

    你也可以试试这个:sync.Map

    Map 类似于 Go 的 map[interface{}]interface{},但它可以安全地被多个 goroutine 并发使用,而无需额外的锁定或协调。加载、存储和删除以摊销的常数时间运行。

    Map 类型针对两种常见用例进行了优化:(1) 当给定键的条目只被写入一次但读取多次时,例如在只会增长的缓存中,或 (2) 当多个 goroutine 读取时,为不相交的键集写入和覆盖条目。

    在这两种情况下,与使用单独的 Mutex 或 RWMutex 配对的 Go map 相比,使用 Map 可以显着减少锁争用。

    注意:在第三段中,它提到了为什么使用 sync.Map 比使用 Go Map 与 sync.RWMutex 简单配对更有益。

    所以这完全符合你的情况,我猜?

    【讨论】:

    • 只有一个 sync.Map 并不能保证每个映射键最多创建一个实例,这可能是也可能不是问题。
    【解决方案3】:

    有点晚了,无论如何这应该会有所帮助:https://github.com/ashwinshirva/api/tree/master/dp/singleton

    这里展示了两种实现单例的方式:

    1. 使用sync.Mutex
    2. 使用sync.Once

    【讨论】:

      猜你喜欢
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多