Go Channel 通道

本文最后更新于:3 年前

Go channel

基本语法和需要注意的点

  1. 语法定义
1
var channel chan [type]
* 使用 `<-` 传递数据
* `chan <- data` 发送数据到通道,向通道中写数据
* `data <- chan` 获取通道中的数据,从通道中读取数据
  1. 注意的点
    • 它是用于 goroutine 之间进行传递消息的
    • 每个 channel 都有相关联的数据类型, nil chan不能使用
    • channel 是在 goroutine 之间链接,数据接收和发送必须处于不同的 goroutine
    • 非缓冲通道发送数据和读取数据都是阻塞的,直到另一条 goroutine 执行读取或写完数据才会解除阻塞
    • channel 是同步的,就意味着同一时间,只能有一条 goroutine 来操作
    • 不要忘记 close(channel) 关闭通道

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main

import (
"fmt"
"strconv"
)

func main() {

// 创建通道
var channel chan int
fmt.Printf("%T,%v\n", channel, channel) // chan int,<nil>
channel = make(chan int)
fmt.Printf("%T,%v\n", channel, channel) // chan int,0xc00008c060

// 通道内写入数据
go setData(channel)
// 读取通道内的数据
for v := range channel {
fmt.Println("读取的数据: ", v) // 读取的数据:0,1,2,3,4
}

// 非缓冲通道
var ch1 chan int
ch1 = make(chan int)
go func() {
for i := 0; i < 5; i++ {
fmt.Println("子的 goroutine 中,i", i) // 子的 goroutine 中,i 0,1,2,3,4
}
// 循环结束后向通道中写数据,表示结束了。
ch1 <- 1
fmt.Println("结束")
}()

data := <-ch1
fmt.Println("main data --> ", data)

/**
缓冲通道(固定大小)
接收:缓冲区数据空了会阻塞
写入:缓冲区数据满了会阻塞
*/
ch2 := make(chan int, 3)
fmt.Println(len(ch2), cap(ch2)) // 0 ,3
ch2 <- 1
ch2 <- 2
ch2 <- 3
fmt.Println(len(ch2), cap(ch2)) // 3,3
// 缓冲区满了,如果需要继续写入数据,需要有其他的 goroutine 进行读取(队列的结构来读取)
// ch2 <- 4
ch3 := make(chan string, 3)
fmt.Println(len(ch3), cap(ch3)) // 0 ,3
go setStringData(ch3, 3)
for {
v, ok := <-ch3
if !ok {
fmt.Println("读取完毕", ok) // 读取完毕 false
break
}
fmt.Println("读取的数据是:", v) // 读取的数据是: 0,1,2
}

/**
双向通道
chan ch
chan <- data 写入数据
data <- chan 读取数据
*/
ch4 := make(chan string)
isDone := make(chan bool)
go SendString(ch4, isDone)
data1 := <-ch4 // 读取
fmt.Println(data1) // golang
ch4 <- "learn golang" // 发送

<-isDone // 判断这个来看主程序结束

/**
单向通道:定向
chan <- Write 只支持写
<- chan Read 只能读
*/
singleChanWrite := make(chan<- int) // 只能写,不能读
singleChanRead := make(<-chan int) // 只能读,不能写

fmt.Println("main over")
}

func setData(ch chan int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch) // 通知对方,通道关闭
}

func setStringData(ch chan string, number int) {
for i := 0; i < number; i++ {
ch <- strconv.Itoa(i)
}
close(ch) // 通知对方,通道关闭
}

func SendString(ch chan string, isDone chan bool) {
ch <- "golang" // 发送
data2 := <-ch // 读取数据
fmt.Println("main goroutine 传来: ", data2) // main goroutine 传来: learn golang

isDone <- true // 限制主程序过快的结束执行
}