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 具备以下特点:

  1. 有缓冲 channel 的内部有一个缓冲队列;
  2. 发送操作是向队列的尾部插入元素,如果队列已满,则阻塞等待,直到另一个 goroutine 执行,接收操作释放队列的空间;
  3. 接收操作是从队列的头部获取元素并把它从队列中删除,如果队列为空,则阻塞等待,直到另一个 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)

}