4 回答

TA貢獻(xiàn)1906條經(jīng)驗 獲得超10個贊
sq
這種情況是函數(shù)的輸出通道沒有緩沖造成的。所以sq
等待下一個函數(shù)從輸出中讀取,但如果sq
不是異步的,它就不會發(fā)生:
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貢獻(xiàn)1772條經(jīng)驗 獲得超6個贊
你的函數(shù)創(chuàng)建一個通道,寫入它,然后返回它。寫入將阻塞,直到有人可以讀取相應(yīng)的值,但這是不可能的,因為此函數(shù)之外還沒有人擁有通道。
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
}
如果將循環(huán)包裝在 goroutine 中,則允許循環(huán)和函數(shù)sq繼續(xù);即使循環(huán)阻塞,return out語句仍然可以繼續(xù),最終您將能夠?qū)㈤喿x器連接到通道。
(在 goroutines 之外的通道上循環(huán)本質(zhì)上沒有什么壞處;你的main函數(shù)無害且正確地完成了它。)

TA貢獻(xiàn)1871條經(jīng)驗 獲得超8個贊
代碼有點復(fù)雜,我們簡化一下
下面的第一個 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)
}
}
死鎖的原因是主協(xié)程中沒有等待的緩沖通道。
兩種解決方案
// 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貢獻(xiàn)1934條經(jīng)驗 獲得超2個贊
死鎖的原因是因為 main 正在等待 returnsq和 finish,而 thesq正在等待有人讀取 chan 然后它可以繼續(xù)。
我通過刪除 sq 調(diào)用層來簡化您的代碼,并將一個句子分成 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不會阻塞,消費結(jié)果隊列,willgoroutine繼續(xù),就沒有阻塞了。
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 關(guān)注
- 175 瀏覽
添加回答
舉報