1. channel介绍
2. 通过channel实现同步
import (
"fmt"
"time"
)
var ch = make(chan int)
func Printer(str string) {
for _, data := range str {
fmt.Printf("%c", data)
time.Sleep(time.Second)
}
fmt.Printf("\n")
}
//person1执行完成后,才能到person2执行
func person1(str string) {
Printer(str)
ch <- 666 //会给管道写数据,发送
}
func person2(str string) {
<- ch //从管道取数据,接收,如果管道没有数据它就阻塞
Printer(str)
}
func main() {
//新建2个协程,
go person1("hello")
go person2("world")
for {
}
}
3.通过channel实现同步和数据交换
func main() {
go func() {
defer fmt.Printf("子协程调用完毕")
for i:=0; i<5; i++ {
fmt.Println("this is a new task, i=", i)
time.Sleep(time.Second)
}
ch <- 123
}()
<- ch //没有数据前,阻塞
fmt.Printf("主线程调用完毕")
}
channel 的类型
channel 分为不带缓存的 channel 和带缓存的 channel。
无缓存的 channel
从无缓存的 channel 中读取消息会阻塞,直到有 goroutine 向该 channel 中发送消息;同理,向无缓存的 channel 中发送消息也会阻塞,直到有 goroutine 从 channel 中读取消息。
通过无缓存的 channel 进行通信时,接收者收到数据 happens before 发送者 goroutine 唤醒
4. 无缓存的 channel
从无缓存的 channel 中读取消息会阻塞,直到有 goroutine 向该 channel 中发送消息;同理,向无缓存的 channel 中发送消息也会阻塞,直到有 goroutine 从 channel 中读取消息。
通过无缓存的 channel 进行通信时,接收者收到数据 happens before 发送者 goroutine 唤醒
5. 有缓存的 channel
有缓存的 channel 的声明方式为指定 make 函数的第二个参数,该参数为 channel 缓存的容量
ch := make(chan int, 10)
有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息。
func main() {
//创建一个有缓存到channel
var ch = make(chan int, 5)
go func() {
for i:=0; i< 10; i++ {
ch <- i
fmt.Println("this is new task, i=", i)
time.Sleep(time.Second*2)
}
}()
for m:=0; m<10; m++ {
fmt.Println("this is main task, m=", m)
<- ch
//time.Sleep(time.Second)
}
}
6. 关闭channel
7. 通过range遍历channel内容
func main() {
var ch = make(chan int, 5)
go func() {
for i:=0; i<10; i++ {
ch <- i
}
close(ch)
fmt.Println("new task is closed")
}()
for {
//通过range遍历channel内容
for num := range ch {
fmt.Println("rum=", num)
}
}
}
8. 单方向的channel