免费个人微网站模板,东莞理工学院教务处,电商网站用什么做最好,杭州seo网络推广Golang中的channel为什么要使用channelchannel的介绍channel的基本使用定义/声明channel管道的遍历和关闭channel的关闭channel的遍历goroutine和channel结合应用实例1应用实例2案例注意事项为什么要使用channel
前面使用全局变量加锁同步来解决goroutine的通讯#xff0c;但…
Golang中的channel为什么要使用channelchannel的介绍channel的基本使用定义/声明channel管道的遍历和关闭channel的关闭channel的遍历goroutine和channel结合应用实例1应用实例2案例注意事项为什么要使用channel
前面使用全局变量加锁同步来解决goroutine的通讯但不完美
1.主线程在等待所有goroutine全部完成时间很难确定我们这里设置10秒仅仅是过段2.如果主线程休眠时间长了会加长等待时间如果等待时间短了可能还有routine处于工作状态这时也会随主线程的退出而销毁3.通过全局白能量加锁同步来实现通讯也并不利用多个协程对全局变量的读写操作4.上面种种分析都在互换一个新的通讯机制-----channel
channel的介绍
1.channel本质就是一个数据结构-队列2.数据是先进先出3.线程安全多goroutine访问时不需要加锁就是说channel本身就是线程安全的4.channel是有类型的一个string的channel只能存放string类型数据
channel的基本使用
定义/声明channel
var 变量名chan数据类型
举例
var intChan chan int (intChan用于存放int数据)
var mapChan chan map[int]ssting (mapChan用于存放map[int]string类型)
var perChan chan Person
var perChan2 chan *Person
说明
channel是引用类型
channel必须初始化才能写入数据即make后才能使用
管道是有类型的intChan只能写入整数
package mainimport fmtfunc main() {//演示一下管道的使用//创建一个可以存放三个int类型的俄管道var intChan chan intintChan make(chan int, 3)//看看intChan是什么fmt.Printf(intChan的值%v intChan本身的地址%p\n, intChan, intChan)//向管道写入数据intChan - 10num : 211intChan - num//看看管道的长度和cap(容量fmt.Printf(channel len %v cap%v \n, len(intChan), cap(intChan))//从管道中读取数据var num2 intnum2 -intChanfmt.Println(num2, num2)fmt.Printf(channel len %v cap%v \n, len(intChan), cap(intChan))//在没有使用协程的情况下如果我们管道数据已经全部取出在取就会报告deadlock
}
/*
intChan的值0xc00010e080 intChan本身的地址0xc000006028
channel len 2 cap3
num2 10
channel len 1 cap3
*/
管道的遍历和关闭
channel的关闭
使用内置函数close可以关闭channel当channel关闭后就不能再想channel写数据了但是仍然可以从给channel读取数据
channel的遍历
channel支持for-range的方式进行遍历
1.在遍历时如果channel没有关闭则会出现deadlock的错误
2.在遍历时如果channel已经关闭则会出现正常遍历数据遍历完后就会退出遍历
package mainimport fmtfunc main() {intChan : make(chan int, 3)intChan - 100intChan - 200close(intChan)//这时不能够再写入到channel//intChan - 300fmt.Println(okk)n1 : -intChanfmt.Println(n1, n1)//遍历管道intChan2 : make(chan int, 100)for i : 0; i 100; i {intChan2 - i * 2 //放入100个数据到管道}// 在遍历时如果channel没有关闭责护出现deadlock的错误close(intChan2)for v : range intChan2 {fmt.Println(v, v)}}
goroutine和channel结合
应用实例1 package mainimport (fmttime
)func writeData(intChan chan int) {for i : 1; i 50; i {//放入数据intChan - ifmt.Println(writeData, i)time.Sleep(time.Second)}close(intChan) //关闭
}//read data
func readData(intChan chan int, exitChan chan bool) {for {v, ok : -intChanif !ok {break}time.Sleep(time.Second)fmt.Printf(readData读到数据%v\n, v)}//readData读取完数据后即任务完成exitChan - trueclose(exitChan)
}func main() {//创建两个管道intChan : make(chan int, 50)exitChan : make(chan bool, 1)go writeData(intChan)go readData(intChan, exitChan)//time.Sleep(time.Second * 10)for {_, ok : -exitChanif !ok {break}}
}
应用实例2
如果只是向管道写入数据而没有读取就会出现阻塞而dead lock原因是intChan容量是10而带点吗writeData会写入50个数据因此就会阻塞在writeData的ch-i
案例 package mainimport fmtfunc putNum(intChan chan int) {for i : 1; i 8000; i {intChan - i}//关闭intChanclose(intChan)
}//开启四个协程从intChan取出数据并判断是否为素数
//如果是就放入到primeChan
func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {//使用for循环var flag boolfor {num, ok : -intChanif !ok {break}flag true //假定是素数//判断num是不是素数for i : 2; i num; i {if num%i 0 { //说明该num不是素数flag falsebreak}}if flag {//将这个数就放入到primeChanprimeChan - num}}fmt.Println(有一个primeNum协程因为取不到数据退出)//这里还不能关闭primeChan//向exitChan写入trueexitChan - true
}func main() {intChan : make(chan int, 1000)primeChan : make(chan int, 2000) //放入结果//标识退出的管道exitChan : make(chan bool, 4)//开启一个协程想in特产放入1-8000个数go putNum(intChan)//开启四个协程从intChan取出数据并判断是否为素数//如果是就放入到primeChanfor i : 0; i 4; i {go primeNum(intChan, primeChan, exitChan)}//这里进行主线程处理go func() {for i : 0; i 4; i {-exitChan}//当我们从exitChan去出了4个结果就可以放心关闭primeChanclose(primeChan)}()//遍历primeNum把结果输出for {res, ok : -primeChanif !ok {break}//将结果输出fmt.Printf(素数%d\n, res)}fmt.Println(main线程退出)
}
注意事项
1.channel可以声明为只读或者只写性质2.channel只读和只写的最佳实践案例
package mainimport fmtfunc main() {//管道可以声明为只读或者只写//默认情况下管道是双向的//var chan1 chan int//声明为只写var chan2 chan- intchan2 make(chan int, 3)chan2 - 20//num : -chan2fmt.Println(chan2, chan2)//声明为只读var chan3 -chan intnum2 : -chan3fmt.Println(num2, num2)
}
3.使用select可以解决从管道取数据的阻塞问题4.goroutine中使用recover解决携程中出现panic导致程序奔溃问题 说明如果我们起了一个协程但是这个协程出现了panic如果我们没有捕获这个panic就会造成整个程序崩溃这是我们可以在goroutine中使用recover来捕获panic进行处理这样及时这个协程发生的问题但是主线程仍然不受影响