Go基础知识复习之goroutine

上一篇我们已经知道go语言的strconv包
今天介绍goroutine

在go里面 每一个并发执行的活动成为goroutine
goroutine可以认为是轻量级的线程,与创建线程相比,创建成本和开销都很小
当一个程序启动的时候,只有一个goroutine来调用main函数,称它为主goroutine,
新的goroutine通过go语句进行创建。
在函数的使用前面增加关键字 go 就可以创建一个并发运行的新goroutine。
示例:
package main import( "fmt" ) func hello(){ fmt.Println("this is hello") } func main(){ fmt.Println("this is main") //如果只是调用函数 那么执行顺序是自上而下的 因为hello的调用是存在于main的goroutine中 //加上 关键字go 看看会发生什么情况? go hello() }

通过上述的例子,可以看到,调用hello函数之后 并不会出现结果
为什么呢?
因为此时执行hello函数的goroutine是不属于main函数的 ,main函数执行this is main的输出之后,就结束了
那么如何让hello函数成功调用并输出呢
package main import( "fmt" "time" ) func hello(){ fmt.Println("this is hello") } func main(){ fmt.Println("this is main") //新建一个goroutine go hello() //再建一个goroutine for i:=1; i<=5; i++{ go func(i int){ fmt.Println(i) }(i) } //给main函数设置休眠时间 让负责调用hello函数的goroutine有时间去执行 time.Sleep(time.Second) }

多个goroutine 上面的写法不够规范严谨,可以通过导入sync包的WaitGroup来完善!
需要用到三个方法
  1. Add() 新增一个goroutine
  2. Done() 减去一个goroutine
  3. Wait() 等待
package mainimport( "fmt" "sync" "math/rand" "time" ) //声明结构体等待组 等待让goroutine去结束goroutine的结束 意味着 对应的函数 也就结束了 var wg sync.WaitGroup //示例1:返回随机数的函数 func f(){ //goroutine进来就消费一个所以是Done这里需要defer 为什么呢 因为可以保证在函数返回和赋值之间去执行 defer wg.Done() //这里就需要配置时间种子 让每次goroutine执行的时候产生的时间不同 rand.Seed(time.Now().UnixNano()) //输出一定数量的随机数 for i:=0; i<5; i++{ //返回随机长度的int随机数 r1:=rand.Int() //返回长度为0到10长度的随机数 r2:=rand.Intn(10) fmt.Println(r1,r2) } } //示例2:传入参数返回本身 func f2(i int){ defer wg.Done() fmt.Println(i) } func main(){ //新增 wg.Add(1) //开启运行goroutine go f() for u:=0; u<10; u++{ wg.Add(1) go f2(u) } //结束了 呈现等待 wg.Wait() }

通过上面的示例,在多个goroutine一起执行的情况下,是处于并行的状态去执行,所以每次运行出来的结果都是不一样的。
GMP 先了解:
一个操作系统的线程 对应多个的 goroutine
go程序可以同事使用多个操作系统线程
goroutine 和 OS 线程是 多对多的关系
所谓的GMP,我们在这里拆开:
G表示goroutine
M表示和操作系统映射的关系
P表示调度者队列
模拟把多个goroutine分配给多个操作系统进行执行
package mainimport( "fmt" "runtime" "sync" )var wg sync.WaitGroup func a(){ defer wg.Done() for i:=0; i<10; i++{ fmt.Printf("A:%d \n",i) } } func b(){ defer wg.Done() for j:=0; j<10; j++{ fmt.Printf("a:%d \n",j) } } func main(){ //输出逻辑核心数 fmt.Println(runtime.NumCPU()) runtime.GOMAXPROCS(1)//给一个CPU的逻辑核心数进行处理 wg.Add(2) go a() go b() wg.Wait() }

【Go基础知识复习之goroutine】关于goroutine的介绍先到这边,可能不太明确是什么,但是先知道有这么个东西,后续的文章会去加固这方面的知识!
未完待续。。。

    推荐阅读