Go基础编程:并发编程—goroutine

  • A+
所属分类:Golang

1 goroutine是什么

goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。

2 创建goroutine

只需在函数调⽤语句前添加 go 关键字,就可创建并发执⾏单元。开发⼈员无需了解任何执⾏细节,调度器会自动将其安排到合适的系统线程上执行。

在并发编程里,我们通常想讲一个过程切分成几块,然后让每个goroutine各自负责一块工作。当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。

示例代码:

```
package main

import (
"fmt"
"time"
)

func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
}

func main() {
//创建一个 goroutine,启动另外一个任务
go newTask()

i := 0
//main goroutine 循环打印
for {
    i++
    fmt.Printf("main goroutine: i = %d\n", i)
    time.Sleep(1 * time.Second) //延时1s
}

}
```

程序运行结果:
这里写图片描述

3 主goroutine先退出

主goroutine退出后,其它的工作goroutine也会自动退出:

```
func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
}

func main() {
//创建一个 goroutine,启动另外一个任务
go newTask()

fmt.Println("main goroutine exit")

}
```

程序运行结果:
这里写图片描述

4 runtime包

4.1 Gosched

runtime.Gosched() 用于让出CPU时间片,让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。

这就像跑接力赛,A跑了一会碰到代码runtime.Gosched() 就把接力棒交给B了,A歇着了,B继续跑。

示例代码:

```
func main() {
//创建一个goroutine
go func(s string) {
for i := 0; i < 2; i++ {
fmt.Println(s)
}
}("world")

for i := 0; i < 2; i++ {
    runtime.Gosched() //import "runtime"
    /*
        屏蔽runtime.Gosched()运行结果如下:
            hello
            hello

        没有runtime.Gosched()运行结果如下:
            world
            world
            hello
            hello
    */
    fmt.Println("hello")
}

}
```

4.2 Goexit

调用 runtime.Goexit() 将立即终止当前 goroutine 执⾏,调度器确保所有已注册 defer 延迟调用被执行。

示例代码:

```
func main() {
go func() {
defer fmt.Println("A.defer")

    func() {
        defer fmt.Println("B.defer")
        runtime.Goexit() // 终止当前 goroutine, import "runtime"
        fmt.Println("B") // 不会执行
    }()

    fmt.Println("A") // 不会执行
}() //别忘了()

//死循环,目的不让主goroutine结束
for {
}

}
```

程序运行结果:
这里写图片描述

4.3 GOMAXPROCS

调用 runtime.GOMAXPROCS() 用来设置可以并行计算的CPU核数的最大值,并返回之前的值。

示例代码:

```
func main() {
//n := runtime.GOMAXPROCS(1) //打印结果:111111111111111111110000000000000000000011111...
n := runtime.GOMAXPROCS(2) //打印结果:010101010101010101011001100101011010010100110...
fmt.Printf("n = %d\n", n)

for {
    go fmt.Print(0)
    fmt.Print(1)
}

}
```

在第一次执行(runtime.GOMAXPROCS(1))时,最多同时只能有一个goroutine被执行。所以
会打印很多1。过了一段时间后,GO调度器会将其置为休眠,并唤醒另一个goroutine,这时候就开始打印很多0了,在打印的时候,goroutine是被调度到操作系统线程上的。

在第二次执行(runtime.GOMAXPROCS(2))时,我们使用了两个CPU,所以两个goroutine可以一起被执行,以同样的频率交替打印0和1。

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin