理念

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

GO 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)
}