GO channel
原创
©著作权归作者所有:来自51CTO博客作者mb6300b232419d1的原创作品,请联系作者获取转载授权,否则将追究法律责任
理念
GO语言并发模型CSP: 提倡通过通信共享内存,而非通过共享内存实现通信。
如果说goroutine
是Go程序并发的执行体,channel
就是它们之间的连接。channel
是可以让一个goroutine
发送特定值到另一个goroutine
的通信机制
示例
关闭后任然可以读取
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
a, ok1 := <-ch
b, ok2 := <-ch
c, ok3 := <-ch
fmt.Println(a, ok1)
fmt.Println(b, ok2)
fmt.Println(c, ok3)
}
执行:
1 true
2 true
0 false
异常示例
# 无缓冲通道导致异常
import "fmt"
func baseTest() {
ch := make(chan int)
ch <- 10
fmt.Println("发送成功")
}
func main() {
baseTest()
}
执行:fatal error: all goroutines are asleep - deadlock!
原因:ch := make(chan int) 创建的是无缓冲通道,只有在有地接收值时才会发送成功。
# 通道无空间,继续读取
func testClose() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
//close(ch)
a, ok1 := <-ch
b, ok2 := <-ch
c, ok3 := <-ch
fmt.Println(a, ok1)
fmt.Println(b, ok2)
fmt.Println(c, ok3)
}
执行:fatal error: all goroutines are asleep - deadlock!
# 关闭后,任往通道发送
func main() {
ch := make(chan int, 2)
ch <- 1
close(ch)
ch <- 2
a, ok1 := <-ch
b, ok2 := <-ch
c, ok3 := <-ch
fmt.Println(a, ok1)
fmt.Println(b, ok2)
fmt.Println(c, ok3)
}
执行:
panic: send on closed channel
#解1:无缓冲通道
import "fmt"
func recv(ch chan int) {
ret := <- ch
fmt.Println("接收成功: ", ret)
}
func unBuffer() {
ch := make(chan int)
go recv(ch)
ch <- 10
fmt.Println("发送成功")
}
func main() {
unBuffer()
}
执行:
接收成功: 10
发送成功
#解2:有缓冲通道
import "fmt"
func buffer() {
ch := make(chan int, 2)
ch <- 10
fmt.Println("发送成功")
}
func main() {
buffer()
}
执行:
发送成功
问题:当发送到chan大于其长度,并且没有消费时,造成死锁
import "fmt"
func buffer() {
ch := make(chan int, 2)
ch <- 10
ch <- 11
ch <- 12
fmt.Println("发送成功")
}
func main() {
buffer()
}
执行:
fatal error: all goroutines are asleep - deadlock!
综合示例
读取对通道a中的数字,在通道b中平方
package main
import (
"fmt"
"sync"
)
var wg2 sync.WaitGroup
func f1(ch1 chan int) {
defer wg2.Done()
for i := 0; i < 100; i++ {
ch1 <- i
}
close(ch1)
}
func f2(ch1, ch2 chan int) {
defer wg2.Done()
for {
x, ok := <-ch1
if !ok {
break
}
ch2 <- x * x
}
close(ch2)
}
func testClose() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
a, ok1 := <-ch
b, ok2 := <-ch
c, ok3 := <-ch
fmt.Println(a, ok1)
fmt.Println(b, ok2)
fmt.Println(c, ok3)
}
func main() {
//testClose()
a := make(chan int, 100)
b := make(chan int, 100)
wg2.Add(2)
go f1(a)
go f2(a, b)
wg2.Wait()
for x := range b {
fmt.Println(x)
}
}
执行:
0
1
4
9
16
...
单向通道
<-chan:只做输出的通道
chan<-:只做输入的通道
示例: 重写上面例子中f2
func f2Uni(ch1 <-chan int, ch2 chan<- int) {
defer wg2.Done()
for {
x, ok := <-ch1
if !ok {
break
}
ch2 <- x * x
}
close(ch2)
}