go 协程
Goroutine是Go运行时管理的轻量级线程 主线程结束时,协程会被中断,需要有效的阻塞机制 协程的使用 package main import ( "fmt" "time" )
go 协程
发布时间:2023-10-06 (2023-10-06)

Goroutine是Go运行时管理的轻量级线程

主线程结束时,协程会被中断,需要有效的阻塞机制

协程的使用

package main

import (
  "fmt"
  "time"
)

// SendCode 发送验证码
func SendCode() {
  fmt.Println("发送验证码开始")
  time.Sleep(3 * time.Second)
  fmt.Println("发送验证码完成!")
}

func main() {
  // 实现用户注册功能
  fmt.Println("用户注册校验完成")
  // 发送验证码
  //SendCode() // 会阻塞主线程
  go SendCode() // 会阻塞主线程
  fmt.Println("验证码已发送,请注意查收...")
}

问题:

  1. 主线程结束,协程也会结束
  2. 协程安全
  3. 如何获取协程函数的返回值,如何在协程中传递数据?

WaitGroup

前面我们通过让主程序延时的方式,可以成功让协程函数顺利结束

但是,延时多久没人能够知道

所以,睡眠这种方式肯定不靠谱

go 自带一个WaitGroup可以解决这个问题, 代码如下

package main

import (
    "sync"
)

var wg sync.WaitGroup

func say(s string) {
    for i := 0; i < 5; i++ {
        println(s)
    }
    wg.Done()
}

func main() {
    wg.Add(2)
    
    go say("Hello")
    go say("World")
    
    wg.Wait()
}

wg.add(2)是有2个goroutine需要执行

wg.Done 相当于 wg.Add(-1) 意思就是我这个协程执行完了。wg.Wait() 就是告诉主线程要等一下,等他们2个都执行完再退出

协程安全

非常经典的例子,两个协程函数,分别对同一个全局变量进行操作

按照我们预期的结果,应该是200万,但是多运行几次,会发现结果各不相同

这就是协程安全问题

package main

import (
  "fmt"
  "sync"
)

var w = sync.WaitGroup{}
var num = 0

func AddNum() {
  for i := 0; i < 1000000; i++ {
    num++
  }
  w.Done()
}

func main() {
  w.Add(2)
  go AddNum()
  go AddNum()
  w.Wait()
  fmt.Println(num)

}

这种情况我们可以通过加锁进行解决,go语言中给我们通过了这个方法

package main

import (
  "fmt"
  "sync"
)

var lock = sync.Mutex{}
var w = sync.WaitGroup{}
var num = 0

func AddNum() {
  lock.Lock()  // 上锁
  for i := 0; i < 1000000; i++ {
    num++
  }
  lock.Unlock() // 解锁
  w.Done() 
}

func main() {
  w.Add(2)
  go AddNum()
  go AddNum()
  w.Wait()
  fmt.Println(num)

}