Goroutine 在 Windows 和 Linux 上的行为不同
Goroutine behaves differently on Windows and Linux
我是 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。但它在 windows 上失败,在
上出现 nil 错误
selectQuery, err := db.Prepare(`
这对我来说很有意义,因为 db 在 feedChan goroutine 启动后初始化。对我来说没有意义的是为什么它适用于 linux。
所以问题是为什么这段代码在 linux 时没有错误?
那可能是 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
`)
// ...
}
在阅读了你的函数的第一行之后,我只能说你的遗留代码有一个 巨大的 错误,只需移动这一行就可以轻松修复它 go feedChan()
到 init()
函数的末尾。
另请注意,主要原因不是竞争条件,只是等待 db 变量正确初始化的问题。
我是 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。但它在 windows 上失败,在
上出现 nil 错误selectQuery, err := db.Prepare(`
这对我来说很有意义,因为 db 在 feedChan goroutine 启动后初始化。对我来说没有意义的是为什么它适用于 linux。
所以问题是为什么这段代码在 linux 时没有错误?
那可能是 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
`)
// ...
}
在阅读了你的函数的第一行之后,我只能说你的遗留代码有一个 巨大的 错误,只需移动这一行就可以轻松修复它 go feedChan()
到 init()
函数的末尾。
另请注意,主要原因不是竞争条件,只是等待 db 变量正确初始化的问题。