Skip to main content

channel的应用

四 channel的一些示例

4.1 示例一 限制并发

耗时操作为timeMore,现在有100个并发,限制为5个:

package main

import (
"time"
"fmt"
)

func timeMore(ch chan string) {

// 执行前先注册,写不进去就会阻塞
ch <- "任务"

fmt.Println("模拟耗时操作")
time.Sleep(time.Second) // 模拟耗时操作

// 任务执行完毕,则管道中销毁一个任务
<-ch
}

func main() {

ch := make(chan string, 5)

// 开启100个协程
for i := 0; i < 100; i++ {
go timeMore(ch)
}

for {
time.Sleep(time.Second * 5)
}
}

4.2 生产者消费者模型

package main

import (
"fmt"
"time"
)

// 生产者
func producer(ch chan<- int) {
i := 1
for {
ch <- i
fmt.Println("Send:", i)
i++
time.Sleep(time.Second * 1) // 避免数据流动过快
}
}

// 消费者
func consumer(ch <-chan int) {
for {
v := <-ch
fmt.Println("Receive:", v)
time.Sleep(time.Second * 2) // 避免数据流动过快
}
}

func main() {

// 生产消费模型中的缓冲区
ch := make(chan int, 5)
// 启动生产者
go producer(ch)
// 启动消费者
go consumer(ch)
// 阻塞主程序退出
for {

}
}

当然,该模型也可以使用无缓冲模型,区别如下:

  • 无缓冲生产消费模型:同步通信
  • 有缓冲生产消费模型:异步通信

4.3 定时器

定时器time.Timer的底层其实也是一个管道。

type Timer struct {
C <-chan Time
r runtimeTimer
}

在时间到达之前,没有数据写入,则timer.C会一直阻塞,直到时间到达,系统会自动向timer.C中写入当前时间,阻塞就会被解除:

    // 创建定时器 定义延迟时间为2秒
layTimer := time.NewTimer(time.Second * 2)
// 从管道取数据,但是一直都是空的,阻塞中,直到2庙后有数据才能取出
fmt.Println(<-layTimer.C)

定时器的其他操作:

  • Stop():停止定时器,此时如果从管道中取数据,则会阻塞
  • Reset():重置定时器,此时需要传入一个新的定时时间间隔
  • timer.Tiker:可以创建一个周期定时器