我是GO的新手。我有以下遗留代码。
var db *sql.DB
func init() {
go feedChan()
connString := os.Getenv("DB_CONN")
var err error
db, err = sql.Open("postgres", connString)
if err != nil {
log.Fatalf("Failed to connect to database at %q: %q\n", connString, err)
}
// confirm connection
if err = db.Ping(); err != nil {
log.Fatalf("Unable to ping database at %q: %q\n", connString, err)
}
}
func feedChan() {
selectQuery, err := db.Prepare(`
SELECT id, proxy
FROM proxy
WHERE fail_count < 2
ORDER BY date_added DESC, last_used ASC, fail_count ASC
LIMIT 5
`)
....
以下代码适用于linux。但是在
上出现nil错误的Windows上失败了selectQuery, err := db.Prepare(`
这对我有意义,因为db在feedChan goroutine启动后初始化。对我来说没有意义的是为什么它适用于linux。
所以问题是为什么这段代码在linux上没有错误?
答案 0 :(得分:1)
那可能是race condition。导入"time"
,将此行放在go feedChan()
之后,看看它是否仍适用于Linux:
time.Sleep(3 * time.Second)
为了避免这种情况,您可以在生成例程(使用db
之前)初始化db
或使用某种barrier :
func init() {
barrier := make(chan int)
go feedChan(barrier)
connString := os.Getenv("DB_CONN")
var err error
db, err = sql.Open("postgres", connString)
if err != nil {
log.Fatalf("Failed to connect to database at %q: %q\n", connString, err)
// Retry.
} else {
barrier <- 1 // Opens barrier.
}
// ...
}
func feedChan(barrier chan int) {
<-barrier // Blocks until db is ready.
selectQuery, err := db.Prepare(`
SELECT id, proxy
FROM proxy
WHERE fail_count < 2
ORDER BY date_added DESC, last_used ASC, fail_count ASC
LIMIT 5
`)
// ...
}
答案 1 :(得分:0)
在阅读了函数的第一行后,我可以说你的遗留代码有一个巨大的错误,只需将此行go feedChan()
移动到结尾即可轻松修复init()
函数。
另请注意,主要原因不是竞争条件,只是等待 db 变量的正确初始化。