package main
import "fmt"
import "runtime"
import "time"
func check(id int) {
fmt.Println("Checked", id)
<-time.After(time.Duration(id)*time.Millisecond)
fmt.Println("Woke up", id)
}
func main() {
defer runtime.Goexit()
for i := 0; i <= 10; i++ {
fmt.Println("Called with", i)
go check(i)
}
fmt.Println("Done for")
}
我是Go的新手,所以任何指针都会很棒。我该如何调试这样的事情?
您可以运行代码段http://play.golang.org/p/SCr8TZXQUE
更新:这在游乐场没有<-time.After(time.Duration(id)*time.Millisecond)
行,我想知道为什么? (正如@dystroy所说,这可能是因为游乐场处理时间的方式)
当我在本地尝试时,这是输出:
Called with 0
Called with 1
Checked 0
Called with 2
Checked 1
Called with 3
Checked 2
Called with 4
Woke up 0
Checked 3
Called with 5
Checked 4
Called with 6
Checked 5
Called with 7
Checked 6
Called with 8
Checked 7
Called with 9
Checked 8
Called with 10
Checked 9
Woke up 1
Done for
Checked 10
Woke up 2
Woke up 3
Woke up 4
Woke up 5
Woke up 6
Woke up 7
Woke up 8
Woke up 9
Woke up 10
throw: all goroutines are asleep - deadlock!
goroutine 2 [syscall]:
created by runtime.main
/tmp/bindist046461602/go/src/pkg/runtime/proc.c:221
goroutine 5 [timer goroutine (idle)]:
created by addtimer
/tmp/bindist046461602/go/src/pkg/runtime/ztime_amd64.c:69
exit status 2
所有goroutine都完成但无论如何都会陷入僵局。我应该注意,如果使用定时器无关紧要,无论如何都会死锁。
答案 0 :(得分:7)
来自the documentation of Goexit:
Goexit终止调用它的goroutine。没有其他goroutine受到影响。 Goexit在终止goroutine之前运行所有延迟调用。
您正在退出主程序。别。正如您所做的那样,在go check(i)
启动的最后一个完成之后,没有任何例程运行,因此“死锁”。只需删除此行:
defer runtime.Goexit()
如果你想要的是主要等待一组goroutine完成,你可以使用sync.WaitGroup:
package main
import (
"fmt"
"sync"
"time"
)
func check(id int, wg *sync.WaitGroup) {
fmt.Println("Checked", id)
<-time.After(time.Duration(id)*time.Millisecond)
fmt.Println("Woke up", id)
wg.Done()
}
func main() {
var wg sync.WaitGroup
for i := 0; i <= 10; i++ {
wg.Add(1)
fmt.Println("Called with", i)
go check(i, &wg)
}
wg.Wait()
fmt.Println("Done for")
}
编辑:
如果你在golang的游乐场测试它,任何time.After
都会死锁,因为游戏中的时间被冻结,Goexit可能会退出一个标准程序中甚至不存在的例程。
答案 1 :(得分:0)
所有goroutine都在等待某人使用<-time.After
中发送的值。
您可以删除<-
或make main消耗您启动的所有goroutines的值。
修改强>
这对我有用
package main
import "fmt"
//import "runtime"
import "time"
func check(id int) {
fmt.Println("Checked", id)
<-time.After(time.Duration(id)*time.Millisecond)
fmt.Println("Woke up", id)
}
func main() {
//defer runtime.Goexit()
for i := 0; i <= 10; i++ {
fmt.Println("Called with", i)
go check(i)
}
fmt.Println("Done for")
}
女巫与之前提出的解决方案相同,因此我将提出一个没有等待组的解决方案
package main
import "fmt"
import "time"
func check(id int, c chan bool) {
fmt.Println("Checked", id)
time.After(time.Duration(id)*time.Millisecond)
fmt.Println("Woke up", id)
c <- true
}
func main() {
c := make(chan bool)
for i := 0; i <= 10; i++ {
fmt.Println("Called with", i)
go check(i, c)
}
var n uint
for n<10 {
<- c
n++
}
fmt.Println("Done for")
}