Go 协程
协程
go中并没有线程的概念,且go的协程是由go runtime自己来调度的,对于程序员来说是透明的。
开启一个协程(并发单元)
go function()
channel
不是依靠共享内存来通信,而是用通信来共享内存。channel就是一种通信工具。
声明一个channel
ch := make(chan string)
向channel中写入数据
ch <- "some data"
从channel中读取数据
someData := <- ch
无缓冲channel
channel不存储数据,只传输数据,所以读写channel是同步的。
无缓冲区channel,在写完数据之后,只有当其他goroutine读取走数据之后,才能继续写。
同理,在读取完数据之后,只有其他goroutine写完之后才能继续读。否则就会阻塞。
ch := make(chan string) // 无缓冲区channel
有缓冲区channel
和java的阻塞队列很像。
一个有缓冲 channel 具备以下特点:
- 有缓冲 channel 的内部有一个缓冲队列;
- 发送操作是向队列的尾部插入元素,如果队列已满,则阻塞等待,直到另一个 goroutine 执行,接收操作释放队列的空间;
- 接收操作是从队列的头部获取元素并把它从队列中删除,如果队列为空,则阻塞等待,直到另一个 goroutine 执行,发送操作插入新的元素。
ch := make(chan string,3)
cap(ch) // channel的最大容量
len(ch) // channel当前存储了多少数据
关闭channel
关闭channel后还向channel写数据的话,会引发panic。但是可以读数据,如果channel中没有数据的话,那么读到的是对应类型的0值。
close(ch)
单向channel
只允许读不允许写,或者只允许写不允许读的channel。在语法层面会报错。
readOnlyChan := make( <-chan string)
writeOnlyChan := make(chan<- string)
select+channel模式
select关键字可以监听多个channel的状态,这就是所谓的多路复用。
select { // select同时监听多个channel,那个先好先执行那个
case filePath := <-firstCh:
fmt.Println(filePath)
case filePath := <-secondCh:
fmt.Println(filePath)
case filePath := <-threeCh:
fmt.Println(filePath)
}