【发布时间】: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 它工作正常,我只使用一个数据库连接器对象。
-
“这不是瓶颈吗?”是的,这是互斥体的明确目的,即创建瓶颈以避免并发问题。您说得对,它也可能导致性能问题,但是当在性能和正确性之间进行权衡时,正确性总是更重要;为了提高性能,您必须设法在不牺牲正确性的情况下减少锁定。