go协程的简单用法

参考解析

题目来源:字节跳动

答案:

在Go语言中开一个协程非常方便,在需要通过协程来执行的函数时,直接在函数前加go关键字就可以

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func A(i int) {
  6. fmt.Println("我是A")
  7. }
  8. func main() {
  9. fmt.Println("我是main")
  10. go A(1)
  11. fmt.Println("执行完了")
  12. }
  13. //输出
  14. //我是main
  15. //执行完了

程序正常执行没有报错,但是没有函数A的输出.

这是因为主协程并不会等待子协程执行完才往下走,执行到go后,语句会继续执行,go后面的函数新开一个协程,各跑各的,所以主协程执行完go语句,就无事可做,就退出了.

那怎么让上面的代码打印出函数A的输出.得让主函数待一会儿协程执行完了再退出,或者让主协程不退出,比如在web程序中,主协程是不退出的.

  • 通过sync. WaitGroup的三个方法 Add(), Done(), Wait() 来实现协程的控制
  • 通过带buffer的channel来控制
  • 通过sync. Cond

下面演示下等待协程完成的代码

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. func A(i int) {
  7. fmt.Println("我是A", i)
  8. }
  9. func main() {
  10. var wg sync.WaitGroup
  11. fmt.Println("我是main")
  12. wg.Add(1)
  13. go func(i int) {
  14. defer wg.Done()
  15. A(i)
  16. }(1)
  17. wg.Wait()
  18. fmt.Println("执行完了")
  19. }
  20. //输出
  21. //我是main
  22. //我是A 1
  23. //执行完了

下面演示通过channel来控制协程的流程

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func A(i int) {
  6. fmt.Println("我是A", i)
  7. }
  8. func main() {
  9. ch := make(chan bool, 1)
  10. fmt.Println("我是main")
  11. go func(i int, chp chan<- bool) {
  12. defer close(chp)
  13. A(i)
  14. fmt.Println("finish")
  15. chp <- true
  16. }(1, ch)
  17. fmt.Println("wait")
  18. <-ch
  19. fmt.Println("执行完了")
  20. }
  21. //输出
  22. //我是main
  23. //wait
  24. //我是A 1
  25. //finish
  26. //执行完

下面演示通过sync. Cond来实现

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. func A(i int) {
  7. fmt.Println("我是A", i)
  8. }
  9. func main() {
  10. var locker = new(sync.Mutex)
  11. var cond = sync.NewCond(locker)
  12. var done bool = false
  13. fmt.Println("我是main")
  14. cond.L.Lock()
  15. go func(i int) {
  16. A(i)
  17. fmt.Println("finish")
  18. done = true
  19. cond.Signal()
  20. }(1)
  21. fmt.Println("wait")
  22. if !done {
  23. cond.Wait()
  24. cond.L.Unlock()
  25. }
  26. fmt.Println("执行完了")
  27. }
  28. //输出
  29. //我是main
  30. //wait
  31. //我是A 1
  32. //finish
  33. //执行完了