0%

Go channel

  • chan 基本用法
  • chan 与 select

    chan

    声明 chan

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 声明不带缓冲的通道
    ch1 := make(chan string)

    // 声明带10个缓冲的通道
    ch2 := make(chan string, 10)

    // 声明只读通道
    ch3 := make(<-chan string)

    // 声明只写通道
    ch4 := make(chan<- string)
    注意:
  • 不带缓冲的通道,进和出都会阻塞。
  • 带缓冲的通道,进一次长度 +1,出一次长度 -1,如果长度等于缓冲长度时,再进就会阻塞。

操作 chan

  • 写入 chan
    1
    2
    3
    ch1 := make(chan string, 10)

    ch1 <- "a"
  • 读取 chan
    1
    2
    3
    val, ok := <- ch1
    // 或
    val := <- ch1
  • 关闭 chan close(chan)
    注意:
  • close 以后不能再写入,写入会出现 panic
  • 重复 close 会出现 panic
  • 只读的 chan 不能 close
  • 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
package main

import (
"fmt"
"time"
)

func main() {

c := make(chan int)

go func() {
i := 0
for {
i++
c <- i
fmt.Printf("goroutine writing...i = %d\n", i)
time.Sleep(1 * time.Second)
}
}()

for {
i := <- c
fmt.Printf("main routine reading...i = %d\n",i)
}

}

运行结果:
channel1

close

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
package main

import "fmt"

func main() {
c := make(chan int)

go func() {
for i := 0; i < 5; i++ {
c <- i
//close可以关闭一个channel
close(c)
}
}()

for {
//ok如果为true表示channel没有关闭,如果为false表示channel已经关闭
if data, ok := <-c; ok {
fmt.Println(data)
} else {
break
}
}

fmt.Println("Main Finished..")
}

其中

1
2
for
if data, ok := <-c; ok

可以替换为:

1
2
3
4
//可以使用range来迭代不断操作channel
for data := range c {
fmt.Println(data)
}

select

select 语法

1
2
3
4
5
6
7
8
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
default : /* 可选 */
statement(s);
}

select 语句的语法:

  • 每个 case 都必须是一个通信
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
  • 否则:
    • 如果有 default 子句,则执行该语句。
    • 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 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
package main

import "fmt"

func fibonacci(c, quit chan int) {
x, y := 1, 1

for {
select {
case c <- x:
//如果c可写,则该case就会进来
tmp := x
x = y
y = tmp + y
case <-quit:
fmt.Println("quit")
return
}
}
}

func main() {
c := make(chan int)
quit := make(chan int)

//sub go
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}

quit <- 0
}()

//main go
fibonacci(c, quit)
}