go学习笔记(二)
goroutines and concurrency
使用关键字go func()可以启动一个协程。
1 | package main |
对于这个例子,其中runtime.Gosched()是显示指定让出cpu,执行另一个协程。该例子执行结果为
1 | hello |
如果注释掉runtime.Gosched(),那么结果如下。
1 | hello |
这样的原因是主程序迅速执行完毕,导致协程未执行。
修改代码,在runtime.Gosched()前加一个输出,观察具体的执行过程:
1 | func say(s string) { |
结果为
1 | 1 hello |
可以看到首先执行的是主程序,遇到runtime.Gosched()后执行协程,协程遇到runtime.Gosched()后继续执行主程序。主程序最后一次执行完后退出程序,所以协程少执行一次。
channels
A channel
is like two-way pipeline in Unix shells: use channel
to send or receive data.
1 | ci := make(chan int) |
channel的数据先进先出。如果设置了Buffered channels,也就是固定长度的channel。超出长度后会报错。
从channel获取数据的行为是阻塞的,如果channel内没有数据,读取的行为就会阻塞当前的协程。
- range:可以直接用range对channel进行遍历,
1 | c := make(chan int, 10) |
close:用close关闭channel。
select: select 默认阻塞,当case中的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
38func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
//在这个例子中,如果把fibonacci(c, quit)提前,则会发生死锁。
// func main() {
// c := make(chan int)
// quit := make(chan int)
// fibonacci(c, quit)
// go func() {
// for i := 0; i < 10; i++ {
// fmt.Println(<-c)
// }
// quit <- 0
// }()
// }为了防止一直阻塞,可以设置超时:
1
2
3
4case <-time.After(5 * time.Second):
println("timeout")
o <- true
break
The package runtime
has some functions for dealing with goroutines.
runtime.Goexit()
Exits the current goroutine, but defered functions will be executed as usual.
runtime.Gosched()
Lets the scheduler execute other goroutines and comes back at some point.
runtime.NumCPU() int
Returns the number of CPU cores
runtime.NumGoroutine() int
Returns the number of goroutines
runtime.GOMAXPROCS(n int) int