// 定义一个字符串类型的消息通道
var msgChan chan string
// 为通道分配内存空间,表示通道中可缓存的数据量,不指定时默认为0
msgChan = make(chan string,10)
package main
import (
"fmt"
)
func myFunc(msgChan chan bool) {
fmt.Println("Inside my goroutine")
// 将数据写入通道,此处阻塞直到另一端读取通道
msgChan <- true
}
func main() {
fmt.Println("Hello World")
// 创建一个通道
var msgChan chan bool = make(chan bool)
// 将通道做为参数传入并执行协程
go myFunc(msgChan)
// 从通道中读取数据,此处会阻塞直到另一端写入通道
<-msgChan
fmt.Println("Finished Execution")
}
Hello World
Inside my goroutine
Finished Execution
通道本身并不提供关闭通道的方法,而是通过系统内置的close()方法关闭通道。在通道关闭后再继续往通道写数据会引发panic错误,而读数据则可以持续读取到通道中没有值为止,读取通道支持多参数返回,其中第一个参数表示从通道中读出的值,第二个参数表示是否正确读出数据,在通道关闭的情况下会返回false,可以借此判断通道是否已经关闭
package main
import (
"fmt"
)
func main() {
// 创建一个通道
msgChan := make(chan string, 10)
// 先往通道写入一条记录
msgChan <- "a normal message"
// 关闭通道
close(msgChan)
// 持续从通道中读取数据,ok值为false时,表示通道已经关闭且没有数据
for {
msg, ok:= <-msgChan
if !ok {
fmt.Println("chan already closed")
return
}
fmt.Printf("message: %s\n", msg)
}
}
package main
import (
"fmt"
"sync"
)
// writeChan 将数据写入单向通道
func writeChan(wc chan<- string, wg *sync.WaitGroup) {
wc <- "hello"
wg.Done()
}
// readChan 从单向通道中读取数据并输出
func readChan(rc <-chan string, wg *sync.WaitGroup) {
fmt.Println(<-rc)
wg.Done()
}
func main() {
var waitGroup sync.WaitGroup
var c chan string = make(chan string)
waitGroup.Add(2)
// 将双向通道转为只读通道
go readChan(c, &waitGroup)
// 将双向通道转为只写通道
go writeChan(c, &waitGroup)
waitGroup.Wait()
}
空间大小为0的通道只有在读和写同时进行的情况下两端才会解除阻塞,而在并发场景中,并发量往往不是固定不变的,有时候并发量提升,写通道压力增大,读通道来不及消费,导致越来越多的写通道协程阻塞,内存持续增长,到了一定程度,就会触发系统OOM,进而影响到服务器稳定性。对于高并发的场景,可以提高通道的大小,将无法即时消费的写请求缓存到通道中,释放协程资源。