【发布时间】:2023-02-01 13:39:54
【问题描述】:
问题在于 goOne 和 goTwo 函数都分别向通道 ch1 和 ch2 发送值,但是在 main 函数中没有对应这些值的接收器。这意味着通道被阻塞,程序无法继续。导致main函数中的select语句无法从channels中读取,所以一直执行default case。
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
ch1 := make(chan string)
ch2 := make(chan string)
wg.Add(2)
go goOne(&wg, ch1)
go goTwo(&wg, ch2)
select {
case <-ch1:
fmt.Println(<-ch1)
close(ch1)
case <-ch2:
fmt.Println(<-ch2)
close(ch2)
default:
fmt.Println("Default Case")
}
wg.Wait()
}
func goTwo(wg *sync.WaitGroup, ch2 chan string) {
ch2 <- "Channel 2"
wg.Done()
}
func goOne(wg *sync.WaitGroup, ch1 chan string) {
ch1 <- "Channel 1"
wg.Done()
}
输出:
Default Case
fatal error: all goroutines are asleep - deadlock!
goroutine 1 \[semacquire\]:
sync.runtime_Semacquire(0xc000108270?)
/usr/local/go/src/runtime/sema.go:62 +0x25
sync.(\*WaitGroup).Wait(0x4b9778?)
/usr/local/go/src/sync/waitgroup.go:139 +0x52
main.main()
/home/nidhey/Documents/Go_Learning/goroutines/select.go:29 +0x2af
goroutine 6 \[chan send\]:
main.goOne(0x0?, 0x0?)
/home/nidhey/Documents/Go_Learning/goroutines/select.go:39 +0x28
created by main.main
/home/nidhey/Documents/Go_Learning/goroutines/select.go:14 +0xc5
goroutine 7 \[chan send\]:
main.goTwo(0x0?, 0x0?)
/home/nidhey/Documents/Go_Learning/goroutines/select.go:33 +0x28
created by main.main
/home/nidhey/Documents/Go_Learning/goroutines/select.go:15 +0x119\```
我正在寻找一种不同的模式,例如 select 来处理通道被阻塞的情况。
为了解决这个问题,我在 wg.Wait() 之后的主函数中添加了一个 <-ch1 或 <-ch2 来接收发送到通道的值并解除它们的阻塞
【问题讨论】:
-
您需要提供更多信息,说明您希望通过代码实现什么,以及您期望发生什么。目前还不清楚你是想等待两个 goroutines 完成,还是只等待其中一个。
-
想象一下,如果我们有两个 api 端点,API1 和 API2,它们返回相同的数据但托管在不同的区域。所以我想做的是,我需要在两个不同的函数(即 goroutines)中对两个 api 进行 API 调用,一旦任何一个 api 向我们发送响应,我就想处理接收到的数据。因此,我首先使用选择块检查 whcih api 是否正在获取数据。
-
不能保证执行默认值,它只是在这里执行,因为此时两个通道都没有准备好接收。删除默认值以查看会发生什么(这当然是另一个死锁,因为您正试图从一个只会发送一个值的通道接收两个值)。如果你说你只是在寻找从通道接收到的第一个值,那么将该值分配给一个变量并且不要尝试再次接收。您正在丢弃第一个值。
标签: go concurrency goroutine channels waitgroup