这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战
Goroutine
一种运行在用户态下的轻量级的线程, 称为微线程或协程.
与线程和进程相比, 协程的执行效率高. 无线程和进程切换的开销.
在Go程序启动的时候, main函数也是运行在一个goroutine中, 称为main goroutine
当使用用go来调用一个函数时, 都会再创建一个新的goroutine
goroutine的创建
func sayHi() {
for i := 0; i < 100; i++ {
fmt.Println("我是一个goroutine, ", i)
}
}
// 在函数前面加上关键字: go, 现在就执行了一个goroutine
// 一个goroutine必定对应一个函数, 多个goroutine可以执行相同的函数
// 至此为止, 我们已经学完了
go sayHi()
fmt.Println("我是main函数 , 我执行完了")
// 当main函数执行完毕之后, 未执行完的goroutine也会停止执行
// 比如像这样, 当能在sayHi执行到一半的时候, main函数就执行完了
// 而sayHi函数的执行也会退出
// 我们可以选择让main goroutine晚退出一会, 来让其它goroutine执行完毕
time.Sleep(time.Microsecond * 1000)
sync.WaitGroup
// 创建一个全程的waitGroup
var wg sync.WaitGroup
func sayHi() {
fmt.Println("我是sayHi函数, 我开始执行了")
for i := 0; i < 100; i++ {
fmt.Println("我是一个goroutine, ", i)
}
// 每当程序执行完毕要退出的时候, 调用Done方法
// 表示有一个goroutine执行完毕
wg.Done()
}
// 每当有一个goroutine要开始执行时, 调用Add函数, 进行加1操作
// 表示, waitGroup里又多了一个goroutine在在执行
wg.Add(1)
go sayHi()
// 当waitGroup里没有在执行的goroutine时, 会调用这个方法
wg.Wait()
fmt.Println("我是main函数 , 我执行完了")
开启多个goroutine
var wg sync.WaitGroup
var count int
func sayHello(i int) {
count++
fmt.Println("我是函数sayHello, 我是一个goroutine, ", i)
wg.Done()
}
wg.Add(20)
for i := 0; i < 20; i++ {
go sayHello(i)
}
wg.Wait()
fmt.Println("执行了sayHello: ", count, "次")
fmt.Println("我是main函数 , 我执行完了")
goroutine匿名函数
/*
wg.Add(20)
for i := 0; i < 20; i++ {
// 匿名函数捕获外部变量
go func() {
// 打印i的时候, 会出现多个重复的值
fmt.Println("我是一个匿名函数: ", i)
wg.Done()
}()
}
*/
wg.Add(20)
for i := 0; i < 20; i++ {
// 我们应该使用传参的方式, 来获取外部变量的值
go func(i int) {
fmt.Println("我是一个匿名函数: ", i)
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("我是main函数 , 我执行完了")
GOMAXPROCS
func func1() {
for i := 0; i < 100; i++ {
fmt.Println("我是func1, ", i)
}
}
func func2() {
for i := 0; i < 100; i++ {
fmt.Println("我是func2, ", i)
}
}
func func3() {
for i := 0; i < 100; i++ {
fmt.Println("我是func3, ", i)
}
}
// 指定使用多少个系统态线程来执行goroutine
// 当设置只有一个CPU来执行goroutine时, 我们可以看到一般情况下, 都是执行完一个goroutine, 再执行另一个
// 当有多个CPU来执行goroutine时, 我们可以看到多个goroutine交换的在控制台打印输出
runtime.GOMAXPROCS(3)
go func1()
go func2()
go func3()
fmt.Println("我是main函数, 我完了")
time.Sleep(time.Second)
总结
goroutine是一个轻量级的线程, goroutine的管理是由go实现的调度器来统一管理的.
goroutine和系统中的线程是多对多的关系, 并且我们不需要关心它们是如何调度的.
可以把更多的精力放在业务功能的编写上, 嗯, Golang天生支持并发编程!!!