4 回答
TA贡献1906条经验 获得超10个赞
sq
这种情况是函数的输出通道没有缓冲造成的。所以sq
等待下一个函数从输出中读取,但如果sq
不是异步的,它就不会发生:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
numsCh := gen(3, 4)
sqCh := sq(numsCh) // if there is no sq in body - we are locked here until input channel will be closed
result := sq(sqCh) // but if output channel is not buffered, so `sq` is locked, until next function will read from output channel
for n := range result {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int, 100)
for n := range in {
out <- n * n
}
close(out)
return out
}
TA贡献1772条经验 获得超5个赞
你的函数创建一个通道,写入它,然后返回它。写入将阻塞,直到有人可以读取相应的值,但这是不可能的,因为此函数之外还没有人拥有通道。
func sq(in <-chan int) <-chan int {
// Nobody else has this channel yet...
out := make(chan int)
for n := range in {
// ...but this line will block until somebody reads the value...
out <- n * n
}
close(out)
// ...and nobody else can possibly read it until after this return.
return out
}
如果将循环包装在 goroutine 中,则允许循环和函数sq继续;即使循环阻塞,return out语句仍然可以继续,最终您将能够将阅读器连接到通道。
(在 goroutines 之外的通道上循环本质上没有什么坏处;你的main函数无害且正确地完成了它。)
TA贡献1871条经验 获得超8个赞
代码有点复杂,我们简化一下
下面的第一个 eq,没有死锁
func main() {
send := make(chan int)
receive := make(chan int)
go func() {
send<-3
send<-4
close(send)
}()
go func() {
receive<- <-send
receive<- <-send
close(receive)
}()
for v := range receive{
fmt.Println(v)
}
}
下面的第二个 eq,删除“go”有死锁
func main() {
send := make(chan int)
receive := make(chan int)
go func() {
send<-3
send<-4
close(send)
}()
receive<- <-send
receive<- <-send
close(receive)
for v := range receive{
fmt.Println(v)
}
}
让我们再次简化第二个代码
func main() {
ch := make(chan int)
ch <- 3
ch <- 4
close(ch)
for v := range ch{
fmt.Println(v)
}
}
死锁的原因是主协程中没有等待的缓冲通道。
两种解决方案
// add more cap then "channel<-" time
func main() {
ch := make(chan int,2)
ch <- 3
ch <- 4
close(ch)
for v := range ch{
fmt.Println(v)
}
}
//async "<-channel"
func main() {
ch := make(chan int)
go func() {
for v := range ch {
fmt.Println(v)
}
}()
ch <- 3
ch <- 4
close(ch)
}
TA贡献1934条经验 获得超2个赞
死锁的原因是因为 main 正在等待 returnsq和 finish,而 thesq正在等待有人读取 chan 然后它可以继续。
我通过删除 sq 调用层来简化您的代码,并将一个句子分成 2 个:
func main() {
result := sq(gen(3, 4)) // <-- block here, because sq doesn't return
for n := range result {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
for n := range in {
out <- n * n // <-- block here, because no one is reading from the chan
}
close(out)
return out
}
在sq方法中,如果把代码放入goroutine,willsq返回,main func不会阻塞,消费结果队列,willgoroutine继续,就没有阻塞了。
func main() {
result := sq(gen(3, 4)) // will not blcok here, because the sq just start a goroutine and return
for n := range result {
fmt.Println(n)
}
fmt.Println("Process completed")
}
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n // will not block here, because main will continue and read the out chan
}
close(out)
}()
return out
}
- 4 回答
- 0 关注
- 125 浏览
添加回答
举报