我是靠谱客的博主 昏睡哑铃,这篇文章主要介绍【Go tour】并发章节Go 程信道带缓冲的信道range 和 close,现在分享给大家,希望可以做个参考。

Go 并发编程

  • Go 程
  • 信道
  • 带缓冲的信道
  • range 和 close

Go 程

Go 程(goroutine)是由 Go 运行时管理的轻量级线程。

复制代码
1
2
3
4
5
6
go f(x, y, z) 会启动一个新的 Go 程并执行 f(x, y, z) f, x, y 和 z 的求值发生在当前的 Go 程中,而 f 的执行发生在新的 Go 程中。

Go 程在相同的地址空间中运行,因此在访问共享的内存时必须进行同步。sync 包提供了这种能力,不过在 Go 中并不经常用到,因为还有其它的办法(见下一页)。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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") }
复制代码
1
2
3
4
5
6
7
8
9
10
hello world world hello hello world world hello hello

信道

信道是带有类型的管道,你可以通过它用信道操作符 <- 来发送或者接收值。

复制代码
1
2
3
4
ch <- v // 将 v 发送至信道 ch。 v := <-ch // 从 ch 接收值并赋予 v。 (“箭头”就是数据流的方向。)

和映射与切片一样,信道在使用前必须创建:

复制代码
1
2
ch := make(chan int)

默认情况下,发送和接收操作在另一端准备好之前都会阻塞。这使得 Go 程可以在没有显式的锁或竞态变量的情况下进行同步。

以下示例对切片中的数进行求和,将任务分配给两个 Go 程。一旦两个 Go 程完成了它们的计算,它就能算出最终的结果。

复制代码
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 sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // 将和送入 c } func main() { s := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c // 从 c 中接收 fmt.Println(x, y, x+y)
复制代码
1
2
-5 17 12

带缓冲的信道

信道可以是 带缓冲的。将缓冲长度作为第二个参数提供给 make 来初始化一个带缓冲的信道:

复制代码
1
2
ch := make(chan int, 100)

仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
package main import "fmt" func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) fmt.Println(<-ch) }

正常输出

复制代码
1
2
3
1 2

修改为1

复制代码
1
2
3
4
5
6
fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send]: main.main() /tmp/sandbox3447111331/prog.go:8 +0x4b

将fmt.Println(<-ch) 改为fmt.Println(ch),输出地址值

复制代码
1
2
3
4
0xc00005a070 1

range 和 close

发送者可通过 close 关闭一个信道来表示没有需要发送的值了。接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完

复制代码
1
2
3
v, ok := <-ch 之后 ok 会被设置为 false

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

注意: 只有发送者才能关闭信道,而接收者不能。向一个已经关闭的信道发送数据会引发程序恐慌(panic)。

还要注意: 信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有需要发送的值时才有必要关闭,例如终止一个 range 循环。

复制代码
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" ) 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
11
12
0 1 1 2 3 5 8 13 21 34

最后

以上就是昏睡哑铃最近收集整理的关于【Go tour】并发章节Go 程信道带缓冲的信道range 和 close的全部内容,更多相关【Go内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(90)

评论列表共有 0 条评论

立即
投稿
返回
顶部