golang:为什么这段代码没有死锁?
golang: why there's no deadlock in this code?
golang:为什么这段代码没有死锁?
请完成以下代码:
package main
import (
"fmt"
"time"
)
func f1(done chan bool) {
done <- true
fmt.Printf("this's f1() goroutine\n")
}
func f2(done chan bool) {
val := <-done
fmt.Printf("this's f2() goroutine. val: %t\n", val)
}
func main() {
done1 := make(chan bool)
done2 := make(chan bool)
go f1(done1)
go f2(done2)
fmt.Printf("main() go-routine is waiting to see deadlock.\n")
time.Sleep(5 * time.Second)
}
正如您所见,go-routine f1() 正在向通道发送一个值。 go-routine f2() 正在从通道接收值。
但是,没有从 go-routine f1() 发送到的通道接收 go-routine。
类似地,没有 go-routine 发送到 go-routine f2() 从中接收的通道。
正如@icza 的评论正确指出的那样,当 所有 goroutines 被卡住并且无法取得进展时,就会发生死锁。在你的情况下 f1
和 f2
被卡住了,但主要的 goroutine 没有 - 所以这不是死锁。
但是,它是 goroutine 泄漏!当某些代码完成其逻辑存在但离开 goroutines 运行ning(未终止)时,就会发生 Goroutine 泄漏。我发现像 github.com/fortytw2/leaktest
这样的工具可用于检测 goroutine 泄漏,它可以检测代码中的问题 - 试一试。
这是修改后的代码示例:
import (
"testing"
"time"
"github.com/fortytw2/leaktest"
)
func f1(done chan bool) {
done <- true
fmt.Printf("this's f1() goroutine\n")
}
func f2(done chan bool) {
val := <-done
fmt.Printf("this's f2() goroutine. val: %t\n", val)
}
func TestTwoGoroutines(t *testing.T) {
defer leaktest.CheckTimeout(t, time.Second)()
done1 := make(chan bool)
done2 := make(chan bool)
go f1(done1)
go f2(done2)
}
当你运行这个测试时,你会看到类似的东西:
--- FAIL: TestTwoGoroutines (1.03s)
leaktest.go:132: leaktest: timed out checking goroutines
leaktest.go:150: leaktest: leaked goroutine: goroutine 7 [chan send]:
leaktest-samples.f1(0xc000016420)
leaktest-samples/leaktest1_test.go:45 +0x37
created by leaktest-samples.TestTwoGoroutines
leaktest-samples/leaktest1_test.go:60 +0xd1
leaktest.go:150: leaktest: leaked goroutine: goroutine 8 [chan receive]:
leaktest-samples.f2(0xc000016480)
leaktest-samples/leaktest1_test.go:50 +0x3e
created by leaktest-samples.TestTwoGoroutines
leaktest-samples/leaktest1_test.go:61 +0xf3
正如@icza 所说,主 goroutine 可以继续并最终终止。
如果您从两个函数调用中的任何一个中删除 go
关键字(使它们发生在主 goroutine 上),那么应用程序就会出现死锁。看看这个 go playground(它为你突出了僵局)https://play.golang.org/p/r9qo2sc9LQA
还有一件事。
func f1(done chan bool) {
fmt.Printf("f1()\n")
}
func main() {
done := make(chan bool)
go f1(done)
done <- true
}
在这里,调用者 go-routine 显然卡住了,因为不存在从通道接收的 go-routine。
在这里,并不是所有的 go-routines 都被阻塞了(f1() 漏掉了),但仍然存在死锁。原因是,必须至少有 1 个应该从通道接收的 go 例程。
但这显然与上面的评论相矛盾,并不是所有的 go-routines 都被阻止了。
golang:为什么这段代码没有死锁?
请完成以下代码:
package main
import (
"fmt"
"time"
)
func f1(done chan bool) {
done <- true
fmt.Printf("this's f1() goroutine\n")
}
func f2(done chan bool) {
val := <-done
fmt.Printf("this's f2() goroutine. val: %t\n", val)
}
func main() {
done1 := make(chan bool)
done2 := make(chan bool)
go f1(done1)
go f2(done2)
fmt.Printf("main() go-routine is waiting to see deadlock.\n")
time.Sleep(5 * time.Second)
}
正如您所见,go-routine f1() 正在向通道发送一个值。 go-routine f2() 正在从通道接收值。 但是,没有从 go-routine f1() 发送到的通道接收 go-routine。 类似地,没有 go-routine 发送到 go-routine f2() 从中接收的通道。
正如@icza 的评论正确指出的那样,当 所有 goroutines 被卡住并且无法取得进展时,就会发生死锁。在你的情况下 f1
和 f2
被卡住了,但主要的 goroutine 没有 - 所以这不是死锁。
但是,它是 goroutine 泄漏!当某些代码完成其逻辑存在但离开 goroutines 运行ning(未终止)时,就会发生 Goroutine 泄漏。我发现像 github.com/fortytw2/leaktest
这样的工具可用于检测 goroutine 泄漏,它可以检测代码中的问题 - 试一试。
这是修改后的代码示例:
import (
"testing"
"time"
"github.com/fortytw2/leaktest"
)
func f1(done chan bool) {
done <- true
fmt.Printf("this's f1() goroutine\n")
}
func f2(done chan bool) {
val := <-done
fmt.Printf("this's f2() goroutine. val: %t\n", val)
}
func TestTwoGoroutines(t *testing.T) {
defer leaktest.CheckTimeout(t, time.Second)()
done1 := make(chan bool)
done2 := make(chan bool)
go f1(done1)
go f2(done2)
}
当你运行这个测试时,你会看到类似的东西:
--- FAIL: TestTwoGoroutines (1.03s)
leaktest.go:132: leaktest: timed out checking goroutines
leaktest.go:150: leaktest: leaked goroutine: goroutine 7 [chan send]:
leaktest-samples.f1(0xc000016420)
leaktest-samples/leaktest1_test.go:45 +0x37
created by leaktest-samples.TestTwoGoroutines
leaktest-samples/leaktest1_test.go:60 +0xd1
leaktest.go:150: leaktest: leaked goroutine: goroutine 8 [chan receive]:
leaktest-samples.f2(0xc000016480)
leaktest-samples/leaktest1_test.go:50 +0x3e
created by leaktest-samples.TestTwoGoroutines
leaktest-samples/leaktest1_test.go:61 +0xf3
正如@icza 所说,主 goroutine 可以继续并最终终止。
如果您从两个函数调用中的任何一个中删除 go
关键字(使它们发生在主 goroutine 上),那么应用程序就会出现死锁。看看这个 go playground(它为你突出了僵局)https://play.golang.org/p/r9qo2sc9LQA
还有一件事。
func f1(done chan bool) {
fmt.Printf("f1()\n")
}
func main() {
done := make(chan bool)
go f1(done)
done <- true
}
在这里,调用者 go-routine 显然卡住了,因为不存在从通道接收的 go-routine。
在这里,并不是所有的 go-routines 都被阻塞了(f1() 漏掉了),但仍然存在死锁。原因是,必须至少有 1 个应该从通道接收的 go 例程。 但这显然与上面的评论相矛盾,并不是所有的 go-routines 都被阻止了。