• Golang 并发编程指南


    分享 Golang 并发基础库,扩展以及三方库的一些常见问题、使用介绍和技巧,以及对一些并发库的选择和优化探讨。

    go 原生/扩展库

    提倡的原则

    不要通过共享内存进行通信;相反,通过通信来共享内存。

    Goroutine

    goroutine 并发模型

    调度器主要结构

    主要调度器结构是 M,P,G

    1. M,内核级别线程,goroutine 基于 M 之上,代表执行者,底层线程,物理线程
    2. P,处理器,用来执行 goroutine,因此维护了一个 goroutine 队列,里面存储了所有要执行的 goroutine,将等待执行的 G 与 M 对接,它的数目也代表了真正的并发度( 即有多少个 goroutine 可以同时进行 );
    3. G,goroutine 实现的核心结构,相当于轻量级线程,里面包含了 goroutine 需要的栈,程序计数器,以及所在 M 的信息

    P 的数量由环境变量中的 GOMAXPROCS 决定,通常来说和核心数对应。

    映射关系

    用户空间线程和内核空间线程映射关系有如下三种:

    1. N:1
    2. 1:1
    3. M:N

    调度图

    关系如图,灰色的 G 则是暂时还未运行的,处于就绪态,等待被调度,这个队列被 P 维护

    注: 简单调度图如上,有关于 P 再多个 M 中切换,公共 goroutine 队列,M 从线程缓存中创建等步骤没有体现,复杂过程可以参考文章简单了解 goroutine 如何实现

    goroutine 使用

    • demo1
      go list.Sort()
       
    • demo2
      funcAnnounce(message string, delay time.Duration) {
      gofunc() {
      time.Sleep(delay)
      fmt.println(message)
      }()
      }
       

    channel

    channel 特性

    创建

    1. // 创建 channel
    2. a := make(chan int)
    3. b := make(chan int, 10)
    4. // 单向 channel
    5. c := make(chan<- int)
    6. d := make(<-chan int)

    存入/读取/关闭

    tip:

    v, ok := <-a  // 检查是否成功关闭(ok = false:已关闭)
    

    channel 使用/基础

    1. use channel
    2. ci := make(chan int)
    3. cj := make(chan int, 0)
    4. cs := make(chan *os.File, 100)
    5. c := make(chan int)
    6. go func() {
    7. list.Sort()
    8. c <- 1
    9. }()
    10. doSomethingForValue
    11. <- c
    12. func Server(queue chan *Request) {
    13. for req := range queue {
    14. sem <- 1
    15. go func() {
    16. process(req)
    17. <- sem
    18. }()
    19. }
    20. }
    21. func Server(queue chan *Requet) {
    22. for req := range queue {
    23. sem <- 1
    24. go func(req *Request) {
    25. process(req)
    26. <- sem
    27. }(req)
    28. }
    29. }
    30. func Serve(queue chan *Request) {
    31. for req := range queue {
    32. req := req
    33. sem <- 1
    34. go func() {
    35. process(req)
    36. <-sem
    37. }()
    38. }
    39. }

    channel 使用/技巧

    等待一个事件,也可以通过 close 一个 channel 就足够了。。

    1. c := make(chan bool)
    2. go func() {
    3. // close 的 channel 会读到一个零值
    4. close(c)
    5. }()
    6. <-c

    阻塞程序

    开源项目【是一个支持集群的 im 及实时推送服务】里面的基准测试的案例

    资料领取直通车:Golang云原生最新资料+视频学习路线icon-default.png?t=M85Bhttps://docs.qq.com/doc/DTllySENWZWljdWp4

    Go语言学习地址:Golang DevOps项目实战icon-default.png?t=M85Bhttps://ke.qq.com/course/422970?flowToken=1043212

    取最快结果

    1. func main() {
    2. ret := make(chan string, 3)
    3. for i := 0; i < cap(ret); i++ {
    4. go call(ret)
    5. }
    6. fmt.Println(<-ret)
    7. }
    8. func call(ret chan<- string) {
    9. // do something
    10. // ...
    11. ret <- "result"
    12. }

    协同多个 goroutines

    注: 协同多个 goroutines 方案很多,这里只展示 channel 的一种。

    1. limits := make(chan struct{}, 2)
    2. for i := 0; i < 10; i++ {
    3. go func() {
    4. // 缓冲区满了就会阻塞在这
    5. limits <- struct{}{}
    6. do()
    7. <-limits
    8. }()
    9. }

    搭配 select 操作

    1. for {
    2. select {
    3. case a := <- testChanA:
    4. // todo a
    5. case b, ok := testChanB:
    6. // todo b, 通过 ok 判断 tesChanB 的关闭情况
    7. default:
    8. // 默认分支
    9. }
    10. }

    main go routinue 确认 worker goroutinue 真正退出的方式

    1. func worker(testChan chan bool) {
    2. for {
    3. select {
    4. // todo some
    5. // case ...
    6. case <- testChan:
    7. testChan <- true
    8. return
    9. }
    10. }
    11. }
    12. func main() {
    13. testChan := make(chan bool)
    14. go worker(testChan)
    15. testChan <- true
    16. <- testChan
    17. }

    关闭的 channel 不会被阻塞

    1. testChan := make(chan bool)
    2. close(testChan)
    3. zeroValue := <- testChan
    4. fmt.Println(zeroValue) // false
    5. testChan <- true // panic: send on closed channel

    注: 如果是 buffered channel, 即

  • 相关阅读:
    ansible 中的变量及加密
    [附源码]计算机毕业设计springboot房屋租赁系统
    课程目录《C语言程序设计:一个小球的编程之旅》
    C++:多态、多态的实现及优点、虚函数(纯虚函数)
    一、CSS文本样式[文本基础、文本样式、段落控制]
    QPair的介绍及用法
    Intel汇编语言程序设计(第7版)第六章编程学习过程中写的小例子
    贝锐蒲公英异地组网方案,如何阻断网络安全威胁?
    合成数据在计算机视觉任务中的应用指南
    maven报错:[ERROR] 不再支持源选项 7。请使用 8 或更高版本。
  • 原文地址:https://blog.csdn.net/weixin_52183917/article/details/127770021