【问题标题】:How does a mutex lock work with a singleton?互斥锁如何与单例一起使用?
【发布时间】:2020-09-24 09:25:12
【问题描述】:

我用 db 连接器实现了单例。 它工作正常,但我无法理解 LOCK (mutex.Lock()) 正在做什么。

我试图理解这一点,但也许这里有人可以告诉我更多关于此的事情。

我是这样理解的-> 在我使用 Lock() 之后,我在 Lock 和 Unlock 之间的整个代码可以由一个 goroutine 运行。 如果这是事实,那不是瓶颈吗?这不是让我的应用程序这么慢吗?每个 gorutine 都必须等待另一端执行这段代码。

package singleton

import (
    "database/sql"
    "fmt"
    "sync"
)

var connector *sql.DB
var mutex = &sync.Mutex{}

func OpenConnection() *sql.DB {
    if connector == nil {
        mutex.Lock()
        defer mutex.Unlock()
        if connector == nil {
            fmt.Println("Creating Single Instance Now")
            var err error
            connector, err = sql.Open("mysql", "db_user:.db_password@/books")

            if err != nil {
                panic(err)
            }
        }
    }

    return connector
}
package server

import (
    "connection/singleton"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "strings"
)

var connector *sql.DB

func SelectQuery(query string) (*sql.Rows, error) {
    connector = singelton.OpenConnection()
    query = strings.ToLower(query)
    if !strings.Contains(query, "select") {
        panic("Can't use select query to run different query")
    }

    results, err := connector.Query(query)

    if err != nil {
        panic(err.Error()) // proper error handling instead of panic in your app
    }

    return results, err
}

【问题讨论】:

  • 1.你的实现被破坏了;双重锁定不起作用。你的代码很活泼。 2. 互斥锁是很常见的东西,只要读一读它们是如何工作的。 3. 打开与数据库的连接只需要一次,而不是针对每个请求。 4. 是的,这将是一个可怕的瓶颈,但无论如何你都不应该这样做。
  • 嗯,你在哪里看到双重锁定?我只有一个 mu.Lock() 我用这篇文章制作了这个代码:progolang.com/how-to-implement-singleton-pattern-in-go
  • 抱歉,“双重锁定”不是最好的术语(双重检查单例更好):检查 == nil 然后锁定,然后重新检查 == nil 完全 b> wrong 因为它是 racy 和 racy 代码在 Go 中是 always wrong 。甚至您从中获取此代码的文章也指出:“从技术上讲,它仍然是错误的方法。” (这篇文章的错误在于它不是 99.99% 的时间是正确的,它是 100% 的错误,因为从来没有一个活泼的代码是正确的)。如果你想要一个单例,请使用 sync.Once(如文章所述)。跨度>
  • 你说“活泼的代码”是什么意思,我按照你的建议修改了代码,我得到了这个:pastebin.com/Gg54tHRc 它工作正常,我只使用一个数据库连接器对象。
  • “这不是瓶颈吗?”是的,这是互斥体的明确目的,即创建瓶颈以避免并发问题。您说得对,它也可能导致性能问题,但是当在性能和正确性之间进行权衡时,正确性总是更重要;为了提高性能,您必须设法在不牺牲正确性的情况下减少锁定。

标签: go locking mutex


【解决方案1】:

我是这样理解的 -> 在我使用 Lock() 之后,我在 Lock 和 Unlock 之间的整个代码可以由一个 goroutine 运行。如果这是事实,那不是瓶颈吗?这不是让我的应用程序这么慢吗?每个 gorutine 都必须等待另一端执行此代码。

我们在这里使用互斥锁的原因是只初始化一次数据库连接。这只会在开始时发生。一旦获得连接,OpenConnection 将始终返回连接而不进入互斥块。 所以不会有任何性能问题。

您也可以使用sync.Once 方法实现相同的目的,而无需使用互斥锁和双重检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多