我正在學習Go通過編寫一個簡單的程序,同時從幾個http服務器下載傳感器數據文件。服務器上的傳感器數據文件會定期刷新(30秒或2分鐘,取決於「原點」)。下載數據可能需要100ms到10秒。所以我讀了每個服務器的一些配置(OriginContext)。然後我爲每個OriginContext啓動一個控制器。每個控制器不斷地啓動下載等的goroutine。我如何在這裏混淆了goroutines中變量的範圍和指針?
我把我的代碼剝離到一個最小的例子,希望仍然顯示我的意圖。當我運行它時,會有兩個控制器,但不知何故,當他們啓動doStuffThatMayTakeLongTime()方法時,它們都引用相同的配置。
那麼,我怎麼在這裏混淆了goroutines中變量的範圍和指針呢?
我對Go很新,也是第一次嘗試使用使用指針的語言。那麼,我害羞的C/C++嘗試已經超過十年了...所以我認爲我的混淆是參考/價值/取消引用,但我看不到它。
這是代碼:
package main
import (
"log"
"time"
)
type OriginContext struct {
Origin string
Offset time.Duration
Interval time.Duration
}
type Controller struct {
originContext *OriginContext
}
func NewController(originContext *OriginContext) (w *Controller) {
log.Printf("Controller starting loop for origin %s.", originContext.Origin)
w = &Controller{originContext}
w.start()
return w
}
func (w *Controller) start() {
log.Println("start() of", w.originContext.Origin)
go func() {
time.Sleep(w.originContext.Offset)
ticker := time.NewTicker(w.originContext.Interval)
go w.doStuffThatMayTakeLongTime() // iteration zero
for {
select {
case <-ticker.C:
go w.doStuffThatMayTakeLongTime()
}
}
}()
}
func (w *Controller) doStuffThatMayTakeLongTime() {
log.Printf("%s doing stuff", w.originContext.Origin)
}
func main() {
contexts := []OriginContext{
{
Origin: "alpha",
Offset: 0 * time.Second,
Interval: 5 * time.Second,
},
{
Origin: "bravo",
Offset: 5 * time.Second,
Interval: 10 * time.Second,
},
}
for _, ctx := range contexts {
log.Printf("Starting Controller %s.", ctx.Origin)
_ = NewController(&ctx)
}
select {}
}
這是一些輸出:
2015/09/07 14:30:11 Starting Controller alpha.
2015/09/07 14:30:11 Controller starting loop for origin alpha.
2015/09/07 14:30:11 start() of alpha
2015/09/07 14:30:11 Starting Controller bravo.
2015/09/07 14:30:11 Controller starting loop for origin bravo.
2015/09/07 14:30:11 start() of bravo
2015/09/07 14:30:16 bravo doing stuff
2015/09/07 14:30:16 bravo doing stuff
2015/09/07 14:30:26 bravo doing stuff
2015/09/07 14:30:26 bravo doing stuff
應該有alpha和bravo 做的東西,但只是喝彩。
嘗試記錄:''NewController'函數開始處的'log.Printf(「控制器以地址%v處的上下文開始,originContext)''。你應該看到兩次相同的地址。 – LeGEC