上一篇我们已经知道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
来完善!需要用到三个方法
- Add() 新增一个goroutine
- Done() 减去一个goroutine
- 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,我们在这里拆开:模拟把多个goroutine分配给多个操作系统进行执行
G表示goroutine
M表示和操作系统映射的关系
P表示调度者队列
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的介绍先到这边,可能不太明确是什么,但是先知道有这么个东西,后续的文章会去加固这方面的知识!
未完待续。。。
推荐阅读
- 对GO切片的理解
- 小程序商城网站开发秒杀模块篇
- 盲盒购物网站系统开发建设 第三篇
- Netty核心概念之ChannelHandler&Pipeline&ChannelHandlerContext
- 简单的线程池实现多线程对大文件的读取
- SSH 端口转发与 SOCKS 代理
- Ubuntu16.04/Scala2.11.8安装教程
- 学习PHP中的高精度计时器HRTime扩展
- 使用OpenResty+Lua实现灰度测试(金丝雀)
- 使用源码编译安装PHP扩展