Go语言使用go语句开启一个新的运行期线程,即goroutine,以一个不同的、新创建的goroutine来执行一个函数。同一个程序中的所有goroutine共享一个地址空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main 
import (
"fmt"
"time"
)

func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}

func main () {
go say("world")
say("hello")
}
// 该代码的运行结果不唯一,因为是两个goroutine在执行

通道

通道是用来传递数据的数据结构

通道可用于两个goroutine之间通过传递一个指定类型的值来同步运行和通讯。操作符<-用于制定通道的方向,如果未指定方向,则为双向通道。

1
2
3
4
5
ch <- v	// 把v发送到ch
v := <-ch // 从ch接收数据
// 并把值赋给v
// 声明一个通道
ch := make(chan int)

默认情况下,通道是不带缓冲区的。

带缓冲区的通道

通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:

1
ch := make(chan int, 100)

如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。

Go通过range关键字来实现遍历读取到的数据,格式如下:

1
v, ok := <- ch

关闭通道

如果通道接收不到数据后ok就为false,这时通道就可以使用close函数来关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
)

func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x + y
}
close(c)
}

func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}