channel用于goroutine之间的通讯golang
若是不用channel,使用共享全局变量的方式,须要加锁安全
// synchornized 同步 // golang中的 sync包中有互斥锁 var lock sync.Mutex // mutex 互斥 lock.Lock() // 上锁 // 多个goroutine同时对相同的数据进行修改 lock.Unlock() // 解锁
使用同步锁并发效率会很低数据结构
channel主要用于goroutine通讯和解决主线程等待goroutine执行结束再退出的问题并发
chan string
,只能保存string数据var variableName chan dataType
函数
var c1 chan int var c2 chan bool var c3 chan map[int]string
channel 是引用类型,必须初始化后才能使用线程
var c1 chan int c1 = make(chan int, 4) // 使用make函数初始化chan int, 4是容量 // 初识化以后容量不可动态变化,channel不会自动扩容,写入数据时不能超过容量,不然会deadlock // fatal error: all goroutines are asleep - deadlock! c1 <- 666 // 写入数据 num := <- c1 // 取出数据, 每取一个数据,channel长度减一 // 不使用goroutine的状况下 // 当数据所有取出是再对channel取数据会报 deadlock
内置函数close(channel) 能够关闭channel,不能再添加数据,可是能够读取数据code
channel能够用for range方式遍历协程
可是必须是已关闭的channel队列
for range遍历一个未关闭的channel会出现deadlock字符串
c1 := make(chan int, 10) for i:=0; i<10; i++ { c1 <- i } close(c1) for v := range c1 { fmt.Println(v) }
对于一个已关闭的channel读取数据时,若是数据已所有取出,取值状态返回false而不会报错
func main() { c1 := make(chan int, 2) c1 := make(chan int, 2) c1 <- 1 c1 <- 2 c2 <- 1 c2 <- 2 close(c1) <- c1 // 取出值 丢弃不用 1 <- c1 // 2 v, ok := <-c1 // 数据已取完 fmt.Println(v,ok) // 0 false <- c2 // 1 <- c2 // 2 v, ok := <-c2 // 数据已取完 程序到这里会出错 deadlock fmt.Println(v,ok) }
对于已关闭的管道,能够在取完数据时结束等待goroutine执行
for { _, ok := <- exitChan bool if !ok { break } }
未关闭的channel须要取出指定个数的值以后结束等待goroutine执行
channel默认是既能够读又能够写的
能够声明为只读或只写
var c1 <- chan int // 只读 var c2 chan <- int // 只写
通常channel不会声明为只读和只写,而是在声明函数形参的时候使用
var c1 chan string func sendData(c chan <- string) {...} func readData(c <- chan string) {...} // c1是默承认读可写的channel // 当c1做为参数传给 sendData时 在 sendData 函数中只容许对管道进行写操做 // 当c1做为参数传给 readData时 在 readData 函数中只容许对管道进行读操做
goroutine中使用recover函数解决协程中出现的panic ,不影响主线程的执行
defer func() { if err = recover(); err != nil { ...dosomething } }
select用于解决从管道中取数据的阻塞问题
不使用select,在遍历未关闭的管道时会deadlock
然而,不少状况下管道都是未关闭的,由于很差肯定何时关
用select来遍历未关闭管道,不会deaklock
func main() { c1 := make(chan int, 10) c2 := make(chan string, 5) for i := 0; i < 10; i++ { rand.Seed(time.Now().UnixNano()) c1 <- rand.Intn(100) } c2 <- "commerce" c2 <- "corresponding" c2 <- "oblige" c2 <- "decline" c2 <- "praise" label1: for { select { case v := <-c1: fmt.Println(v) case v := <-c2: fmt.Println(v) default: fmt.Println("两个管道都没数据了吧") break label1 } } fmt.Println("adhere") }