go - 例行检查频道范围
问题描述
我已经在 Golang 工作了很长时间。但是我仍然面临这个问题,尽管我知道我的问题的解决方案。但一直不明白为什么会这样。
例如,如果我有如下入站和出站通道的管道情况:
package main
import (
"fmt"
)
func main() {
for n := range sq(sq(gen(3, 4))) {
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
}
close(out)
}()
return out
}
它不会让我陷入僵局。但是,如果我删除出站代码中的 go 例程,如下所示:
func sq(in <-chan int) <-chan int {
out := make(chan int)
for n := range in {
out <- n * n
}
close(out)
return out
}
我收到一个死锁错误。为什么在没有 go 例程的情况下使用 range 循环通道会导致死锁。
解决方案
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
}
推荐阅读
- spartacus-storefront - 如何在 spartacus 中不显示错误功能区的情况下处理全局错误
- modelica - 如何设计Modelica组件的图标?
- google-sheets - 使用 VLOOKUP 从 2 个单独的电子表格中查看 2 列,如果在第二列中找到则应用格式?
- python - Python,需要播放从文本到语音 API 中提取的音频,但我无法将其转换为类似字节的对象
- c# - 我的 MySql 'SELECT' 命令有问题
- python - 命令提示符中未显示 Python 版本
- java - 如何使用 AsyncTask 从 URL 返回单个对象
- java - 我可以使用 UUID 作为模型/pojo 类中使用休眠搜索的 id 字段的数据类型吗
- ruby - 如何使用 Mechanize 登录网站
- visual-studio-code - 自动完成时查看颜色预览的问题