广告位联系
返回顶部
分享到

GO利用channel协调协程的实现介绍

Golang 来源:互联网 作者:佚名 发布时间:2023-05-25 21:47:45 人浏览
摘要

go 当中的并发编程是通过goroutine来实现的,利用channel(管道)可以在协程之间传递数据,实现协程的协调与同步。 使用 新建一个管道,使用make channel 来构建 1 2 3 4 5 6 7 8 // 构建一个缓

go 当中的并发编程是通过goroutine来实现的,利用channel(管道)可以在协程之间传递数据,实现协程的协调与同步。

使用

新建一个管道,使用make channel 来构建

1

2

3

4

5

6

7

8

// 构建一个缓存长度为8 的管道

ch := make(chan int ,8)

// 写入

ch <- 10

// 取出

number := <-ch

// 关闭

close(ch)

注意??: 取数据的时候,如果没得取,会阻塞代码的执行,如果一直没有取到,那就是死锁

实现生产者消费者模式

两个生产者者协程和一个消费者协程

使用waitGroup

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

func main() {  

    ch := make(chan int, 100)  

    wg := sync.WaitGroup{}  

    wg.Add(2)  

    // 生产者

    go func() {  

        defer wg.Done()  

        // 写入数据  

        for i := 0; i < 10; i++ {  

            ch <- i  

        }  

    }()  

    // 生产者

    go func() {  

        defer wg.Done()  

        // 写入数据  

        for i := 0; i < 10; i++ {  

            ch <- i  

        }  

    }()  

    wg2 := sync.WaitGroup{}  

    wg2.Add(1)  

    // 消费者

    go func() {  

        sum := 0  

        fmt.Printf("sum %d \n", sum)  

        for {  

            // 这里会等待  

            temp, ok := <-ch  

            // close 并且 管道为空,ok = false  

            if !ok {    

                break  

            } else {  

                sum += temp  

            }  

        }  

        fmt.Printf("sum %d \n", sum)  

        wg2.Done()  

    }()  

    // 等待俩生产者结束  

    wg.Wait()  

    // 生产数据之后,消费者也并行读完了,此时可以关闭 管道 来 跳出for循环了 

    close(ch)  

    // 等待消费者协程结束  

    wg2.Wait()  

}

使用管道则将wg2相关的代码改掉

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

func main() {  

    //... 

    //...

    ch2 := make(chan struct{}, 0)  

    go func() {  

        sum := 0  

        fmt.Printf("sum %d \n", sum)  

        for {  

            // 这里会等待  

            temp, ok := <- ch  

            // close 并且 管道为空,ok = false  

            if !ok {  

                break  

            } else {  

                sum += temp  

            }  

        }  

        fmt.Printf("sum %d \n", sum)  

        ch2 <- struct{}{}  

    }()  

    // 等待俩生产者结束  

    wg.Wait()  

    // 关闭管道

    close(ch)  

    // 等待消费者协程结束  

    <-ch2

}

实战面试题: 「交替打印数字和字母」

题目

使用两个 goroutine 交替打印序列,一个 goroutine 打印数字, 另外一个 goroutine 打印字母, 最终效果如下:

12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728

解题思路

利用channel的 阻塞 来协调线程,达到线程交叉执行的效果。

代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

func main() { 

    letter, number := make(chan bool), make(chan bool) 

    wait := sync.WaitGroup{} 

    go func() { 

        i := 1 

        for { 

            if <-number { 

                fmt.Print(i) 

                i++ 

                fmt.Print(i) 

                i++ 

                letter <- true 

            } 

        } 

    }() 

    wait.Add(1) 

    go func() { 

        // 获得ASCII码 

        i := 'A' 

        for { 

            if <-letter { 

                // 当前已经超过Z时,无需再打印

                if i > 'Z' { 

                    // 停止等待,并且跳出循环

                    wait.Done() 

                    break 

                } 

                // 将ASCII码强转成字母输出 

                fmt.Print(string(i)) 

                i++ 

                fmt.Print(string(i)) 

                i++ 

                number <- true 

            } 

        } 

    }() 

    // 放行数字打印的阻塞

    number <- true 

    // 等待关闭主线程

    wait.Wait() 

}

其实完全也可以将waitGroup换成管道

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

func main() { 

    letter, number := make(chan bool), make(chan bool) 

    // 再定义一个管道来等待,替代waitGroup的作用

    wait := make(chan bool)

    // 打印数字

    go func() { 

        i := 1 

        for { 

            if <-number { 

                fmt.Print(i) 

                i++ 

                fmt.Print(i) 

                i++ 

                letter <- true 

            } 

        } 

    }() 

    // 打印字母

    go func() { 

        // 获得ASCII码 

        i := 'A' 

        for { 

            if <-letter { 

                if i > 'Z' { 

                    wait <- true 

                    break 

                } 

                // 将ASCII码强转成字母输出 

                fmt.Print(string(i)) 

                i++ 

                fmt.Print(string(i)) 

                i++ 

                number <- true 

            } 

        } 

    }() 

    number <- true 

    // 等待管道取值

    <- wait

}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • Windows下升级go版本过程介绍
    首次安装需要在官网下载 msi 安装包,安装完后 golang 会自动设置环境变量。在命令行可以使用 go version 查看版本信息。 后续如果需要升级
  • GO利用channel协调协程的实现介绍
    go 当中的并发编程是通过goroutine来实现的,利用channel(管道)可以在协程之间传递数据,实现协程的协调与同步。 使用 新建一个管道,使
  • Golang实现CronJob(定时任务)的方法
    最近做了一个需求,是定时任务相关的。以前定时任务都是通过 linux crontab 去实现的,现在服务上云(k8s)了,尝试了 k8s 的 CronJob,由于公司
  • goland中导包报红和go mod问题

    goland中导包报红和go mod问题
    goland导包报红 1. 原理 import的包有两类: (1)在go.mod中有地址的,这种需要拉到gopath/pkg下 (2)没在go.mod的,这种在项目里,import的路径需
  • Hugo游乐场内容初始化示例介绍
    使用Hugo构建站点的体验很棒。 首先是构建速度快,其次是使用起来简单,一个hugo命令,我们的站点就已经就绪。 在构建过程中,Hugo提供了
  • 使用Golang快速构建出命令行应用程序
    在日常开发中,大家对命令行工具(CLI)想必特别熟悉了,如果说你不知道命令工具,那你可能是个假开发。每天都会使用大量的命令行工
  • go开源Hugo站点渲染之模板词法解析

    go开源Hugo站点渲染之模板词法解析
    Deps在准备好NewPathSpec,NewSpec,NewContentSpec,NewSourceSpec后,调用onCreate正式创建HugoSites,并在最后一步,加载模板执行器。 模板执行器只是提
  • 向Rust学习Go考虑简单字符串插值特性示例解析
    fmt.Printf或fmt.Sprintf写拼装字符串业务 在日常开发 Go 工程中,我们经常会用fmt.Printf或fmt.Sprintf去写类似的拼装字符串的业务。 如下代码:
  • Golang实现将中文转化为拼音

    Golang实现将中文转化为拼音
    导语:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英
  • Go语言实现猜谜小游戏

    Go语言实现猜谜小游戏
    本文是介绍用Go实现一个猜谜小游戏,就是程序先生成一个随机数num,然后让用户来猜生成的数是多少,如果猜的数比num小就提示用户猜测的
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计