Go指南学习笔记十三

range和close

发送者可以通过close来关闭channel。
接受者可以通过传入第二个参数来测试channl是否被关闭

1
v, ok := <-ch

循环for i := range c会不断从channl接受值,直到它被关闭。

只有发送者能关闭channel,而不是接收者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)
}
}

输出结果

1
2
3
4
5
6
7
8
9
10
0
1
1
2
3
5
8
13
21
34

select

select使得一个goroutine在多个通讯操作中等待。

select会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个分支。当多个都准备好时,会随机选择一个。

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
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 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)
}

输出结果

1
2
3
4
5
6
7
8
9
10
11
0
1
1
2
3
5
8
13
21
34
quit

默认选择

select中的其他分支都没有准备好的时候,default分支会被执行。
为了非阻塞的发送或者接口,可以使用default分支。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Microsecond)
}
}
}

sync.Mutex

如果只想保证每个时刻,只有一个goroutine能访问一个共享的变量避免冲突怎么办?
这里涉及的概念叫做互斥,使用互斥锁mutex来提供这个限制。
Go标准库中提供了sync.Mutex类型以及两个方法

  • Lock
  • Unlock
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"
"time"
"sync"
)
//并发是安全的
type SafeCounter struct{
v map[string] int
mux sync.Mutex
}
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
//lock之后同一时刻只有一个goroutine能访问c.v
c.v[key]++
c.mux.Unlock()
}
// Value 返回给定 key 的计数器的当前值。
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string] int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}

输出结果

1
1000

如果您觉得对您有帮助,谢谢您的赞赏!