golang中channel的用法
空(nil)读写阻塞,写关闭异常,读关闭空零
给⼀个 nil channel 发送数据,造成永远阻塞 ▪ 从⼀个 nil channel 接收数据,造成永远阻塞
给⼀个已经关闭的 channel 发送数据,引起 panic ▪ 从⼀个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回⼀个零值
⽆缓冲的channel是同步的,⽽有缓冲的channel是⾮同步的
close(ch)关闭channel
等待goroutine完成
package main func main() { println("start main") ch := make(chan bool) go func() { println("come into goroutine") ch <- true }() println("do something else") <-ch close(ch) println("end main") }
打印结果:
start main do something else come into goroutine end main
多个goroutine协同
三个功能不相关的goroutine
最后结果要汇总累加到result
上
package main func main() { println("start main") ch := make(chan int) var result int go func() { println("come into goroutine1") var r int for i := 1; i <= 10; i++ { r += i } ch <- r }() go func() { println("come into goroutine2") var r int = 1 for i := 1; i <= 10; i++ { r *= i } ch <- r }() go func() { println("come into goroutine3") ch <- 11 }() for i := 0; i < 3; i++ { result += <-ch } close(ch) println("result is:", result) println("end main") }
其中一组打印结果:
start main come into goroutine3 come into goroutine2 come into goroutine1 result is: 3628866 end main
Select
两个goroutine
无直接关联,但其中一个先达到某一设定条件便退出或超时退出
package main import "time" func main() { println("start main") cond1 := make(chan int) cond2 := make(chan uint64) go func() { for i := 0; ; i++ { cond1 <- i } }() go func() { var i uint64 for ; ; i++ { cond2 <- i } }() endCond := false for endCond != true { select { case a := <-cond1: if a > 99 { println("end with cond1") endCond = true } case b := <-cond2: if b == 100 { println("end with cond2") endCond = true } case <-time.After(time.Microsecond): println("end with timeout") endCond = true } } println("end main") }
其中打印结果有可能是:
start main
end with cond1
end main
也有可能是:
start main
end with timeout
end main
也可能是:
start main
end with cond2
end main
channel与range
package main import "fmt" func main() { println("start main") ch := make(chan int, 4) go func() { for i := 0; i < 10; i++ { ch <- i } // 如果不关闭channel,会引发panic close(ch) }() for v := range ch { fmt.Println(v) } println("end main") }
打印结果为:
start main 0 1 2 3 4 5 6 7 8 9 end main
无缓冲channel
package main func main() { var ch = make(chan int) ch <- 1 println(<-ch) }
打印结果为:
fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send]: main.main() /tmp/sandbox117018544/main.go:5 +0x60
死锁了,为什么会这样呢,因为ch
是一个无缓冲的channel
,在执行到ch <- 1
就阻塞了当前goroutine
(也就是main函数所在的goroutine
),后面打印语句根本没机会执行
稍加修改即能正常运行
package main func main() { var ch = make(chan int) go func() { ch <- 1 println("sender") }() println(<-ch) }
因为此时ch
既有发送也有接收而且不在同一个goroutine
里面,此时它们不会相互阻塞
package main
func main() {
var ch = make(chan int)
ch <- 1
println(<-ch)
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2019-11-04 程序员刷题必备