浙江省建设工程检测协会网站,贵阳网站设计方案,学全屋定制设计怎么入手,给一个网站如何做推广基本介绍
Channel 是 Go 中的一个核心类型#xff0c;可以把它看成一个管道。 利用通道我们可以在多个 goroutine 之间传递数据。 如果说 Goroutine 是 Go 程序并发的执行体#xff0c;Channel 就是它们之间的连接。 Channel 是可以让一个 Goroutine 发送特定值到另一个 Gor…基本介绍
Channel 是 Go 中的一个核心类型可以把它看成一个管道。 利用通道我们可以在多个 goroutine 之间传递数据。 如果说 Goroutine 是 Go 程序并发的执行体Channel 就是它们之间的连接。 Channel 是可以让一个 Goroutine 发送特定值到另一个 Goroutine 的通信机制。 Channel 像一个传送带或者队列总是遵循先入先出First In First Out的规则保证收发数据的顺序。
基本使用
声明
声明 channel var 变量 chan 元素类型声明的通道后需要使用 make 函数初始化之后才能使用 var ch1 chan int // 声明一个传递整型的通道var ch2 chan bool // 声明一个传递布尔型的通道var ch3 chan string // 声明一个传递字符串的通道 ch1 : make(chan int) // 直接初始化一个无缓冲通道ch2 : make(chan int,2) // 初始化一个带缓冲的通道操作
通道有发送send、接收(receive和关闭close三种操作。发送和接收都使用 - 符号。
发送
使用 - 符号放到通道变量右边就可以把值发送到创建的通道中看起来就像值流向通道中。 ch1 : make(chan int ,1)ch1 -1接收
使用 - 符号放到通道变量左边就可以从通道中接收一个值看起来就像通道中流出一个值到变量中。 ch1 : make(chan int ,1)ch1 -1result : - ch1fmt.Println(result) // 1关闭
使用 close 函数可以把通道关闭 close(ch1)关闭通道特点
虽然关闭通道看起来很简单但是在实际场景中需要特别注意通道的关闭如果不能正确通道会引起一些意想不到的错误。 关闭后的通道有以下特点
对一个关闭的通道再发送值就会导致 panic (demo1)。关闭一个已经关闭的通道会导致 panic (demo2)对一个关闭的通道进行接收会一直获取值直到通道为空 (demo3)。对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值 (demo4)。
demo1 func demo1(){ch1 : make(chan int ,1)close(ch1)ch1 - 1 // panic: send on closed channel}demo2 func demo2(){ch1 : make(chan int ,1)close(ch1)close(ch1) // panic: close of closed channel}demo3 func demo3(){ch1 : make(chan int ,3)for i:0;i3;i{ch1 - i}close(ch1)for v : range ch1{fmt.Println(v)}}如果这里不关闭 ch1 这个通道下面的 for range 会一直去遍历 通道没有值的话就会造成阻塞在主协程里造成阻塞的话就会造成死锁报以下致命错误所以在使用 for range 去遍历通道的时候要注意关闭或者在子协程里去这样使用。 fatal error: all goroutines are asleep - deadlock!demo4 func demo4(){ch1 : make(chan int ,1)ch1 -1close(ch1)fmt.Println(-ch1) //1fmt.Println(-ch1) // 0result , ok : - ch1fmt.Println(result) // 0fmt.Println(ok) //false}通道关闭了是可以继续接收值的如果有值则接收值没有值则返回通道类型的零值如果想知道通道是否关闭可以接收第二个值通过第二个值来判断通道是否关闭
无缓冲通道
通道有两种无缓冲通道和带缓冲通道先看下无缓冲通道。 无缓冲通道发送者和接受者都要存在有一方不存在会导致阻塞。 所以说无缓冲的通道又被称为阻塞的通道。 ch : make(chan int)ch - 10fmt.Println(发送成功)以上代码会报错 fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:为什么会报错呢 我们使用 ch : make(chan int)创建的是无缓冲的通道。 无缓冲的通道只有在有接收方接收值的时候才能发送值但是在一个协程里执行到发送方或者接收方的时候就会阻塞所以需要在两个协程间接收和发送。
代码调整 func demo5(){ch : make(chan int)go func() {result : - chfmt.Println(接收成功,result)}()ch - 10fmt.Println(发送成功)}func demo6(){ch : make(chan int)go func() {ch - 10fmt.Println(发送成功)}()result : - chfmt.Println(接收成功,result)}上面两种形式都可以只要不要造成主协程阻塞就可以主协程如果阻塞了就会报致命错误死锁。
缓冲通道
解决无缓冲通道阻塞死锁的问题就是使用有缓冲的通道。通过缓存的使用可以尽量避免阻塞提高应用的性能。 带缓冲的通道允许发送端的数据发送和接收端的数据获取处于异步状态就是说发送端发送的数据可以放在缓冲区里面可以等待接收端去获取数据而不是立刻需要接收端去获取数据。 我们使用 make 函数在初始化的时候为其指定通道的容量缓冲大小 只要通道的容量大于零那么该通道就是有缓冲的通道通道的容量表示通道中能存放元素的数量。 我们可以使用内置的 len 函数获取通道内元素的数量使用 cap 函数获取通道的容量。 func demo7(){ch : make(chan int ,1) // 创建一个容量为 1 的有缓冲区的通道ch - 10fmt.Println(发送成功)result : - chfmt.Println(接收成功,result)}这个例子中创建了带1个缓冲的通道所以往里面写值的时候没有造成阻塞。 ch : make(chan int ,1) // 创建一个容量为 1 的有缓冲区的通道ch - 10 ch - 10fmt.Println(发送成功)这个例子中第一次写值的时候可以第二次写值的时候就会阻塞然后报死锁错误。
扇入和扇出
扇出/扇入模式是并发编程中常用的设计模式特别是在 Go 语言中。它包括两个阶段
扇出阶段在这个阶段单个 goroutine 将任务广播给多个工作 goroutine扇入阶段在这个阶段这些工作 goroutine 的结果被聚合到一个单一的通道中。
FAN - OUT 扇出 func demo9() {taskChan : make(chan int, 10)quitChan : make(chan int,3)go func() {for i : 1; i 10; i {taskChan - i}close(taskChan)}()go func() {for v : range taskChan{fmt.Println(work 1 处理任务,v)}quitChan -1}()go func() {for v : range taskChan{fmt.Println(work 2 处理任务,v)}quitChan -1}()go func() {for v : range taskChan{fmt.Println(work 3 处理任务,v)}quitChan -1}()- quitChan- quitChan- quitChanfmt.Println(over)}输出结果 work 3 处理任务 2work 3 处理任务 4work 3 处理任务 5work 3 处理任务 6work 3 处理任务 7work 3 处理任务 8work 3 处理任务 9work 3 处理任务 10work 1 处理任务 1work 2 处理任务 3overFAN - IN 扇入
func demo10(){taskChan : make(chan int, 10)quitChan : make(chan int,3)overChan : make(chan int)go func() {for i : 1; i 5; i {taskChan - i}quitChan -1}()go func() {for i : 5; i 10; i {taskChan - i}quitChan -1}()go func() {for v : range taskChan{fmt.Println(work 处理任务,v)}fmt.Println(任务全部处理了)overChan - 1}()-quitChan-quitChanclose(taskChan)-overChanfmt.Println(over)
}work 处理任务 5work 处理任务 6work 处理任务 7work 处理任务 8work 处理任务 9work 处理任务 10work 处理任务 1work 处理任务 2work 处理任务 3work 处理任务 4work 处理任务 5任务全部处理了over