Channel
信道
i := make(chan int) // 整数类型的无缓冲信道
cj := make(chan int, 0) // 整数类型的无缓冲信道
cs := make(chan *os.File, 100) // 指向文件指针的带缓冲信道
无缓冲信道在通信时会同步交换数据,它能确保(两个协程的)计算处于确定状态。接收者在收到数据前会一直阻塞。若信道是不带缓冲的,那么在接收者收到值前,发送者会一直阻塞;若信道是带缓冲的,则发送者仅在值被复制到缓冲区前阻塞;若缓冲区已满,发送者会一直等待直到某个接收者取出一个值为止。若在关闭
无缓冲信道
在无缓存的
var done = make(chan bool)
var msg string
func aGoroutine() {
msg = "你好, 世界"
done <- true
}
func main() {
go aGoroutine()
<-done
println(msg)
}
若在关闭done <- false
依然能保证该程序产生相同的行为。
var done = make(chan bool)
var msg string
func aGoroutine() {
msg = "你好, 世界"
close(done)
}
func main() {
go aGoroutine()
<-done
println(msg)
}
对于从无缓冲
var done = make(chan bool)
var msg string
func aGoroutine() {
msg = "hello, world"
<-done
}
func main() {
go aGoroutine()
done <- true
println(msg)
}
缓冲信道
带缓冲的信道可被用作信号量,例如限制吞吐量。在此例中,进入的请求会被传递给
var sem = make(chan int, MaxOutstanding)
func handle(r *Request) {
sem <- 1 // 等待活动队列清空。
process(r) // 可能需要很长时间。
<-sem // 完成;使下一个请求可以运行。
}
func Serve(queue chan *Request) {
for {
req := <-queue
go handle(req) // 无需等待 handle 结束。
}
}
对于带缓冲的
var limit = make(chan int, 3)
func main() {
for _, w := range work {
go func() {
limit <- 1
w()
<-limit
}()
}
select{}
}
最后一句 select{}
是一个空的管道选择语句,该语句会导致 main
线程阻塞,从而避免程序过早退出。还有for{}
、<-make(chan int)
等诸多方法可以达到类似的效果。因为 main
线程被阻塞了,如果需要程序正常退出的话可以通过调用os.Exit(0)
实现。
内建信道
// Ctrl+C 退出
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
fmt.Printf("quit (%v)\n", <-sig)
Links
- 完成
Go Web Server 并发控制一文 https://github.com/eliben/code-for-blog/blob/master/2019/gohttpconcurrency/channel-manager-server.go TODO!