Channel类型
Channel类型的定义格式如下:
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
它包括三种类型的定义。可选的<-
代表channel的方向。如果没有指定方向,那么Channel就是双向的,既可以接收数据,也可以发送数据。
chan T // 可以接收和发送类型为 T 的数据
chan<- float64 // 只可以用来发送 float64 类型的数据
<-chan int // 只可以用来接收 int 类型的数据
<-
总是优先和最左边的类型结合。
chan<- chan int // 等价 chan<- (chan int)
chan<- <-chan int // 等价 chan<- (<-chan int)
<-chan <-chan int // 等价 <-chan (<-chan int)
chan (<-chan int)
使用make
初始化Channel,并且可以设置容量:
make(chan int, 100)
容量(capacity)代表Channel容纳的最多的元素的数量,代表Channel的缓存的大小。
如果没有设置容量,或者容量设置为0, 说明Channel没有缓存,只有sender和receiver都准备好了后它们的通讯(communication)才会发生(Blocking)。如果设置了缓存,就有可能不发生阻塞, 只有buffer满了后 send才会阻塞, 而只有缓存空了后receive才会阻塞。一个nil channel不会通信。
可以通过内建的close
方法可以关闭Channel。
你可以在多个goroutine从/往 一个channel 中 receive/send 数据, 不必考虑额外的同步措施。
Channel可以作为一个先入先出(FIFO)的队列,接收的数据和发送的数据的顺序是一致的。
Buffered Channels
make的第二个参数指定缓存的大小:ch := make(chan int, 100)
。
通过缓存的使用,可以尽量避免阻塞,提供应用的性能。
/*
并发场景之 仅需任意任务完成
chanel 与buffer chanel区别。buffer有接受者就会拿走不需要等待.chane 阻塞的
buffer channel为防止协程的泄露
*/
直接擼代碼:
package ch20
import (
"fmt"
"runtime"
"testing"
"time"
)
/*
并发场景之 仅需任意任务完成
chanel 与buffer chanel区别。buffer有接受者就会拿走不需要等待.chane 阻塞的
buffer channel为防止协程的泄露
*/
func runTash(id int) string {
time.Sleep(10 * time.Millisecond)
return fmt.Sprintf("The result is from %d", id)
}
func FirstResponse() string {
numOfRunner := 10
ch := make(chan string, numOfRunner)
for i := 0; i < numOfRunner; i++ {
go func(i int) {
ret := runTash(i)
ch <- ret
}(i)
}
return <-ch
}
//并发场景之 :所有任务完成才退出
func AllTaskResponse() string {
numOfRunner := 10
ch := make(chan string, numOfRunner)
for i := 0; i < numOfRunner; i++ {
go func(i int) {
ret := runTash(i)
ch <- ret
}(i)
}
finRet := ""
for i := 0; i < numOfRunner; i++ {
finRet += <-ch + "\n"
}
return finRet
}
func TestFirstRespone(t *testing.T) {
t.Log("Before:", runtime.NumGoroutine())
t.Log(FirstResponse())
t.Log(AllTaskResponse())
time.Sleep(time.Second * 1)
t.Log("After:", runtime.NumGoroutine())
}
Github 下载地址:
https://github.com/yangliuzzu/GO-daily-Study.git