一、无缓存 channel
无缓冲channel 可用于两个goroutine 之间 传递信号,比如以下示例:
顺序打印1 至 100 的奇数和偶数:
import (
"fmt"
"time"
)
func main() {
block := make(chan struct{})
go odd(block)
go even(block)
time.Sleep(time.Second)
fmt.Println("done")
}
func odd(block chan struct{}) {
for i := 1; i < 100; i++ {
<-block
if i%2 == 1 {
fmt.Println("奇数:", i)
}
}
}
func even(block chan struct{}) {
for i := 1; i < 100; i++ {
<-block
if i%2 == 0 {
fmt.Println("偶数:", i)
}
}
}
上面这段代码,我们使用一个无缓冲channel 作为两个gorountie 之间的信号传递的桥梁。
主子 goroutine 之间传递信号
func main() {
block := make(chan struct{})
go func() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
close(block)
}()
<-block
fmt.Println("done")
}
我们使用一个无缓冲channel 作为主子goroutine 之间的信号传递的桥梁,通过信号传递,主gorountine 运行结束直接再退出。
二、有缓冲 channel
有缓冲channel 可以作用于解耦操作,模拟消息队列。“生产者”和“消费者”只需各自处理channel ,实现解耦。
解耦生产者和消费者。
func main() {
task := make(chan int, 10)
go consumer(task)
//生成者
for i := 0; i < 10; i++ {
task <- i
}
time.Sleep(time.Second * 2)
}
func consumer(task <-chan int) {
for i := 0; i < 10; i++ {
go func(id int) {
t := <-task
fmt.Println(id, t)
}(i)
}
}
我们使用一个有缓冲的channel , 将生产者,消费者做解耦操作
输出结果:
三、超时操作和定时器
我们还可以通过select 和channel ,实现超时操作和定时器
超时操作:
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string, 1)
go func() {
time.Sleep(2 * time.Second)
c1 <- "result 1"
}()
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(1 * time.Second):
fmt.Println("timeout 1")
}
c2 := make(chan string, 1)
go func() {
time.Sleep(2 * time.Second)
c2 <- "result 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <-time.After(3 * time.Second):
fmt.Println("timeout 1")
}
}
通过c1 和 c2 两个channel ,分别模拟出超时和未超时场景
定时器:
func main() {
ticker := time.NewTicker(500 * time.Millisecond)
done := make(chan bool)
go func() {
for {
select {
case <-done:
return
case t := <-ticker.C:
fmt.Println("Tick at ", t)
}
}
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
done <- true
fmt.Println("Ticker stopped")
}
我们定义一个打点器,每间隔500Ms执行一次操作,当打点stop时,通过一个无缓冲channel 传递退出信号
三、总结
本文我们介绍了一些关于 Channel 的使用方式,我们在阅读完本文后可以了解无缓冲 channel 作为信号传递的使用方式和有缓冲 channel 解耦操作的方式,以及 channel 与 select 配合使用的用法。