社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
使用内置的make函数,我们可以创建一个channel
// ch has type 'chan int'
ch := make(chan int) // unbuffered channel
ch = make(chan int, 0) // unbuffered channel
ch = make(chan int, 3) // buffered channel with capacity 3
一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine
ch <- x // a send statement
x = <-ch // a receive expression in an assignment statement
<-ch // a receive statement; result is discarded
只有发送者需要关闭通道,接收者永远不会需要关闭通道
其实你并不需要关闭每一个channel.
只有当需要告诉接收者goroutine,所有的数据已经全部发送时才需要关闭channel.
不管一个channel是否被关闭,当它没有被引用时将会被Go语言的垃圾自动回收器回收.
关闭一个channels还会触发一个广播机制
所有channel接收者都会在channel关闭时 立刻从阻塞等待中返回 ok值为false 这个广播机制经常被利用进行向多个订阅者同时发送信号 例如退出信号
基于无缓存Channels的发送和接收操作将导致两个goroutine做一次同步操作
一个基于无缓存Channels的发送操作将导致发送者goroutine阻塞,直到另一个goroutine在相同的Channels上执行接收操作.
当发送的值通过Channels成功传输之后,两个goroutine可以继续执行后面的语句.
如果接收操作先发生,那么接收者goroutine也将阻塞,直到有另一个goroutine在相同的Channels上执行发送操作.
func main() {
out := make(chan int)
// 这里向out发送数据,但是并没有另外一个goroutine来接收out的值
out <- 2
go func(in chan int) {
fmt.Println(<-in)
}(out)
// fatal error: all goroutines are asleep - deadlock!
}
基于channels发送消息有两个重要方面:
func main() {
conn, err := net.Dial("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
done := make(chan struct{})
go func() {
io.Copy(os.Stdout, conn) // NOTE: ignoring errors
log.Println("done")
done <- struct{}{} // signal the main goroutine
}()
mustCopy(conn, os.Stdin)
conn.Close()
<-done // wait for background goroutine to finish
}
带缓存的Channel内部持有一个元素队列,队列的最大容量是在调用make函数创建channel时通过第二个参数指定的.
向缓存Channel的发送操作就是向内部缓存队列的尾部插入元素,接收操作则是从队列的头部删除元素.
如果内部缓存队列是满的,那么发送操作将阻塞直到因另一个goroutine执行接收操作而释放了新的队列空间.
如果channel是空的,接收操作将阻塞直到有另一个goroutine执行!!!
串联Channels的管道可以用在需要长时间运行的服务中,每个长时间运行的goroutine可能会包含一个死循环,在不同goroutine的死循环内部使用串联的Channels来通信.
如果发送者知道,没有更多的值需要发送到channel的话,那么让接收者也能及时知道没有多余的值可接收将是有用的,因为接收者可以停止不必要的接收等待.在发送方关闭channel即可.
但是在发送方关闭这个channel后,接收方依然会收到一个永无休止的零值序列.
goroutines泄漏,和垃圾变量不同,泄漏的goroutines并不会被自动回收.因此确保每个不再需要的goroutine能正常退出是重要的!!!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!