我正在学习go,我遇到了goroutines
的问题。这是我的代码
package main
import (
"fmt"
"sync"
"time"
)
var counter = 0
var wg = sync.WaitGroup{}
func main() {
ticker := time.NewTicker(time.Second)
go func() {
for range ticker.C {
// wg.Add(1)
// defer wg.Done()
counter++
fmt.Println(counter)
//wg.Done()
}
}()
ticker2 := time.NewTicker(time.Second * 2)
wg.Add(1)
go func() {
for range ticker2.C {
//defer wg.Done()
fmt.Println(counter)
}
}()
wg.Wait()
}
基本上,我想:
counter
goroutine
,每1秒钟不断更新此计数器goroutine
,每两秒钟一次打印此计数器游乐场是here
我尝试使用WaitGroup
,但我没有设法使用它。
使用此级别的代码,我有以下警告:
WARNING: DATA RACE
Read at 0x0000011d8318 by goroutine 8:
runtime.convT2E64()
另一个问题是这个线程安全吗?我的意思是,我可以安全地在两个groroutines之外的main方法中使用counter吗?
答案 0 :(得分:0)
一种方法可能是在打印时向第二次gorutine发送消息。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Start");
counter := 0
printChannel := make( chan int)
done := make(chan struct{} )
go func(done <-chan struct{}, printChannel chan<- int ){
timer := time.NewTicker(time.Second)
bDone := false;
for !bDone {
select {
case <-timer.C:
counter++
if counter%2 == 0 {
printChannel <- counter
}
case <-done:
bDone=true
}
}
}(done, printChannel)
go func(done <-chan struct{}, printChannel <-chan int ){
bDone:=false
for !bDone{
select {
case n := <-printChannel:
fmt.Print(n, " ");
case <-done:
bDone=true
}
}
}(done,printChannel)
//whatever logic to stop
go func() {
<- time.After(21*time.Second)
done <- struct{}{}
}()
<-done
fmt.Println("\nEnd");
}
请注意,这里只有第3个gorutine来完成这个例子
输出:
Start
2 4 6 8 10 12 14 16 18 20
End
为了改善它,您可以在没有bDone变量的情况下进行改进,您可以停止Ticker并在gorutine存在时添加适当的消息。
或者你可能想测试一下&#39; break&#39;带标签退出循环。
当您使用关闭(完成)频道而不是向其发送消息时,您可以测试效果
此外,如果您准备放松读/写顺序,您可以删除printChannel并使第二个gorutine使用另一个每2秒ping一次的自动收报机。