Goroutine在Windows和Linux上表现不同

时间:2016-10-09 16:27:07

标签: go goroutine

我是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上没有错误?

2 个答案:

答案 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 变量的正确初始化。