当我们使用 make 去创建一个 channel 的时候,实际上返回的是一个指向 channel 的指针。
2.2、在 channel 上发送和接收数据(入门案例)
channel 就像一个消息管道,发送者在管道的 a 端发送消息,接收者就在管道的 b 端接收消息,当消息管道里充满了消息,发送者就不能往里面发送消息了,得停一停,只有当接收者从消息管道取出消息,让管道不再满的时候,之前停下的发送者才能继续往管道里发送消息;同理,当管道里没有消息的时候,接收者也得停一停,等发送者往管道里发送了消息,接收者才能继续接收管道里的消息。
接下来以一个经典的生产者—消费者模型,介绍在 channel 上发送和接收数据。
这里,自行车生产商 Producer 是消息的发送者,购买自行车的客户 Consumer 是消息的接收者,自行车商店 Store 就是消息管道,然后这是一个带缓冲的消息管道,缓冲容量是 5,也就是说,这个 Store 里一次最多只能摆放 5 辆自行车,当 Store 里有 5 辆 自行车的时候,Producer 就要停下来歇一歇了。话不多说,直接上代码。
package main
import("fmt""time")type Bike struct{
Id uint32
Brand string
Location string}var Store chan*Bike
var IsFinish chanboolfuncinit(){
//初始化函数,先于 main 函数执行
Store =make(chan*Bike,5)
IsFinish =make(chanbool)}funcProducer(){
//自行车生产者for i :=0; i <10; i++{
//总共生产 10 辆自行车
bike :=&Bike{
Id:uint32(i),
Brand:"凤凰牌",
Location:"上海",}
Store <- bike
fmt.Printf("**%s生产者**:%d号%s牌自行车\n",(*bike).Location,(*bike).Id,(*bike).Brand)
time.Sleep(time.Second *2)//每隔两秒钟生产一辆自行车}//生产完之后,要关闭 Store,等到 Store 里的自行车被消费者买完以后,消费者会通过知道 Store 已经关闭了,而不再继续等待买 Store 里的自行车close(Store)//close 是非常有必要的!}funcConsumer(){
//自行车消费者for{
bike, ok :=<- Store
if bike ==nil&& ok ==false{
break}
fmt.Printf("==%s消费者==:%d号%s牌自行车\n",(*bike).Location,(*bike).Id,(*bike).Brand)
time.Sleep(time.Second *3)//消费者每隔 3 秒钟买一辆自行车}
IsFinish <-true//告诉主线程 Store 里的自行车已经卖完了,生产者也不生产了,可以结束了}funcmain(){
goProducer()goConsumer()<- IsFinish //在 IsFinish <- true 这句代码没执行前,主线程会阻塞在这里,这么做的目的就是防止上面两个协程还没执行完,主线程就提前退出了}
funcTimeout4(){
work :=make(chanstring)
finish :=make(chanbool)gofunc(){
for i :=0; i <5; i++{
time.Sleep(time.Second *1)
work <-"任务"+ strconv.Itoa(i)}}()gofunc(){
for{
select{
case val :=<- work:
fmt.Println(val)if strings.HasSuffix(val,"4"){
finish <-true}case<-time.After(time.Second *3):
fmt.Println("超时了...")}}}()<- finish
}