go语言学习之并发

go 并发

goroutine

  1. goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小
  2. Go语言内部帮你实现了这些goroutine之间的内存共享
  3. 执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务
  4. goroutine比thread更易用、更高效、更轻便
  5. goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过go关键字实现了,其实就是一个普通的函数。
    1
    go hello(a,b,c)

channels

定义一个channel时,也需要定义发送到channel的值的类型,
注意:必须使用make 创建channel
channel通过操作符<-来接收和发送数据

1
2
3
4
5
6
7
var c = make(chan int)
var b = make(chan string)
var c = make(chan interface{})
//存入数据
c <- 'abc'
//取出数据
value := <-c

默认情况下,channel接收和发送数据都是阻塞的

buffered channels (带缓冲的channels)

1
2
3
ch := make(chan type,value)
//创建带有4个缓冲的线程
ch := make(chan type, 4)

注意:

  1. range (使用range方法读取channels里面的数据)
  2. close() 关闭channel,应该在生产者
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 := 1, 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)
}
}

select (switch切换channel)

select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,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 := 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)
}

select设置超时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case v := <- c:
println(v)
case <- time.After(5 * time.Second):
println("timeout")
o <- true
break
}
}
}()
<- o
}

runtime gotoutine

runtime包中有几个处理goroutine的函数:
  • Goexit

退出当前执行的goroutine,但是defer函数还会继续调用

  • Gosched

让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。

  • NumCPU

返回 CPU 核数量

  • NumGoroutine

返回正在执行和排队的任务总数

  • GOMAXPROCS

用来设置可以并行计算的CPU核数的最大值,并返回之前的值。