• Golang使用Channel


    1.使用协程

    1. package main
    2. //使用协程
    3. import (
    4. "fmt"
    5. "strconv"
    6. "time"
    7. )
    8. func test() {
    9. for i := 1; i <= 10; i++ {
    10. fmt.Println("test() hello world" + strconv.Itoa(i))
    11. time.Sleep(time.Second)
    12. }
    13. }
    14. // 主线程和test协程同时运行
    15. func main() {
    16. go test() //开启了一个协程
    17. for i := 1; i <= 10; i++ {
    18. //strconv.Itoa函数:将整型转换为字符串
    19. fmt.Println("main() hello Golang" + strconv.Itoa(i))
    20. time.Sleep(time.Second)
    21. }
    22. }
    1. main() hello Golang1
    2. test() hello world1
    3. main() hello Golang2
    4. test() hello world2
    5. test() hello world3
    6. main() hello Golang3
    7. main() hello Golang4
    8. test() hello world4
    9. test() hello world5
    10. main() hello Golang5
    11. main() hello Golang6
    12. test() hello world6
    13. test() hello world7
    14. main() hello Golang7
    15. main() hello Golang8
    16. test() hello world8
    17. test() hello world9
    18. main() hello Golang9
    19. main() hello Golang10
    20. test() hello world10

    2.使用20个协程计算1到20各个数的阶乘,把结果放到map中

    1. package main
    2. import (
    3. "fmt"
    4. "sync"
    5. "time"
    6. )
    7. //计算1-20的各个数的阶乘,并且把各个数的阶乘放入到map中
    8. //最后显示出来,要求使用goroutine完成
    9. //思路:1.编写一个函数,计算各个数的阶乘,并放入到map中
    10. //2.我们启动的协程多个,统计的结果放入到map中
    11. //3.map应该做出一个全局变量
    12. var (
    13. myMap = make(map[int]int, 20)
    14. //lock是一个全局的互斥锁
    15. //Mutex:互斥
    16. lock sync.Mutex
    17. )
    18. func test(n int) {
    19. res := 1
    20. for i := 1; i <= n; i++ {
    21. res *= i
    22. }
    23. //把结果放入到map中
    24. //concurrent map writes
    25. //加锁
    26. lock.Lock()
    27. myMap[n] = res
    28. lock.Unlock()
    29. }
    30. func main() {
    31. //开启多个协程完成这个任务
    32. for i := 1; i <= 20; i++ {
    33. go test(i)
    34. }
    35. //让主线程休眠,因为主线程执行完后,协程就会中止
    36. time.Sleep(time.Second * 5)
    37. //输出结果,遍历这个结果
    38. //lock.Lock()
    39. for i, v := range myMap {
    40. fmt.Printf("map[%d]=%d\n", i, v)
    41. }
    42. //lock.Unlock()
    43. }
    1. map[3]=6
    2. map[7]=5040
    3. map[10]=3628800
    4. map[11]=39916800
    5. map[19]=121645100408832000
    6. map[20]=2432902008176640000
    7. map[13]=6227020800
    8. map[9]=362880
    9. map[16]=20922789888000
    10. map[4]=24
    11. map[5]=120
    12. map[6]=720
    13. map[8]=40320
    14. map[15]=1307674368000
    15. map[18]=6402373705728000
    16. map[17]=355687428096000
    17. map[14]=87178291200
    18. map[1]=1
    19. map[2]=2
    20. map[12]=479001600

    3.Channel的使用

    (1).Channel中只能存放指定的数据类型

    (2).Channel数据放满后,就不能放入了

    (3).如果从Channel中取出数据后,可以继续放入

    (4).在没有使用协程的情况下,如果Channel数据取完了,再取,就会报dead lock

    1. package main
    2. import "fmt"
    3. /**
    4. Channel使用注意事项
    5. 1.Channel中只能存放指定的数据类型
    6. 2.Channel数据放满后,就不能放入了
    7. 3.如果从Channel中取出数据后,可以继续放入
    8. 4.在没有使用协程的情况下,如果Channel数据取完了,再取,就会报dead lock
    9. */
    10. //演示管道需求
    11. //channel相当于queue
    12. func main() {
    13. //1.创建一个存放3个int类型的管道
    14. var intChan chan int
    15. //capacity=3
    16. intChan = make(chan int, 3)
    17. //向管道写入数据
    18. intChan <- 10
    19. num := 211
    20. intChan <- num
    21. //4.看看管道的长度和容量
    22. fmt.Printf("channel len=%v cap=%v \n", len(intChan), cap(intChan))
    23. //5.从管道中读取数据
    24. var num2 int
    25. num2 = <-intChan
    26. fmt.Println("num2=", num2)
    27. fmt.Printf("channel len=%v cap=%v \n", len(intChan), cap(intChan))
    28. }
    1. channel len=2 cap=3
    2. num2= 10
    3. channel len=1 cap=3

    4.遍历管道

    1. package main
    2. import "fmt"
    3. // 1.关闭管道,管道不能被写入数据,但是可以取出数据
    4. func test1() {
    5. intChan := make(chan int, 3)
    6. intChan <- 100
    7. intChan <- 200
    8. close(intChan)
    9. intChan <- 300
    10. fmt.Println("Hello")
    11. }
    12. // 遍历管道
    13. func test2() {
    14. intChan := make(chan int, 100)
    15. for i := 0; i < 100; i++ {
    16. intChan <- i * 2
    17. }
    18. //这个方法的前提是Channel要关闭,否则出现deadlock
    19. close(intChan)
    20. for v := range intChan {
    21. fmt.Println("v=", v)
    22. }
    23. }
    24. func main() {
    25. test2()
    26. }

    5.goroutine和channel协同工作案例

    1. package main
    2. import (
    3. "fmt"
    4. "time"
    5. )
    6. /*
    7. *
    8. goroutine和channel协同工作案例
    9. 1.开启一个writeData协程,向管道intChan输入50个整数
    10. 2.开启一个readData协程,从管道intChan中读取writeData写入数据
    11. 3.writeData和readData操作的都是同一条管道
    12. 4.主线程需要等待writeData和readData协程都完成工作才退出
    13. */
    14. func writeData(intChan chan int) {
    15. for i := 1; i <= 50; i++ {
    16. intChan <- i
    17. time.Sleep(time.Second)
    18. fmt.Println("writeData=", i)
    19. }
    20. close(intChan)
    21. }
    22. func readData(intChan chan int, exitChan chan bool) {
    23. for {
    24. v, ok := <-intChan
    25. if !ok {
    26. break
    27. }
    28. time.Sleep(time.Second)
    29. fmt.Println("readData=", v)
    30. }
    31. //读完数据后
    32. exitChan <- true
    33. close(exitChan)
    34. }
    35. func main() {
    36. intChan := make(chan int, 50)
    37. exitChan := make(chan bool, 1)
    38. go writeData(intChan)
    39. go readData(intChan, exitChan)
    40. //time.Sleep(time.Second * 10)
    41. for {
    42. _, ok := <-exitChan
    43. if ok {
    44. break
    45. }
    46. }
    47. }
    1. writeData= 1
    2. readData= 1
    3. readData= 2
    4. writeData= 2
    5. readData= 3
    6. writeData= 3
    7. readData= 4
    8. writeData= 4
    9. readData= 5
    10. writeData= 5
    11. readData= 6
    12. writeData= 6
    13. readData= 7
    14. writeData= 7
    15. readData= 8
    16. writeData= 8
    17. readData= 9
    18. writeData= 9
    19. readData= 10
    20. writeData= 10
    21. readData= 11
    22. writeData= 11
    23. readData= 12
    24. writeData= 12
    25. readData= 13
    26. writeData= 13
    27. readData= 14
    28. writeData= 14
    29. readData= 15
    30. writeData= 15
    31. readData= 16
    32. writeData= 16
    33. readData= 17
    34. writeData= 17
    35. readData= 18
    36. writeData= 18
    37. readData= 19
    38. writeData= 19
    39. readData= 20
    40. writeData= 20
    41. readData= 21
    42. writeData= 21
    43. readData= 22
    44. writeData= 22
    45. readData= 23
    46. writeData= 23
    47. readData= 24
    48. writeData= 24
    49. readData= 25
    50. writeData= 25
    51. readData= 26
    52. writeData= 26
    53. readData= 27
    54. writeData= 27
    55. readData= 28
    56. writeData= 28
    57. readData= 29
    58. writeData= 29
    59. readData= 30
    60. writeData= 30
    61. readData= 31
    62. writeData= 31
    63. readData= 32
    64. writeData= 32
    65. readData= 33
    66. writeData= 33
    67. readData= 34
    68. writeData= 34
    69. readData= 35
    70. writeData= 35
    71. readData= 36
    72. writeData= 36
    73. readData= 37
    74. writeData= 37
    75. readData= 38
    76. writeData= 38
    77. readData= 39
    78. writeData= 39
    79. readData= 40
    80. writeData= 40
    81. readData= 41
    82. writeData= 41
    83. readData= 42
    84. writeData= 42
    85. readData= 43
    86. writeData= 43
    87. readData= 44
    88. writeData= 44
    89. readData= 45
    90. writeData= 45
    91. readData= 46
    92. writeData= 46
    93. readData= 47
    94. writeData= 47
    95. readData= 48
    96. writeData= 48
    97. readData= 49
    98. writeData= 49
    99. readData= 50
    100. writeData= 50

    6.协程求素数

    1. package main
    2. import (
    3. "fmt"
    4. "time"
    5. )
    6. //协程求素数
    7. //要求统计1-200的数字中,哪些是素数?
    8. // 使用并行的方式,将统计素数的任务分配给多个(4个)goroutine去完成
    9. func putNum(intChan chan int) {
    10. for i := 1; i <= 200; i++ {
    11. intChan <- i
    12. }
    13. //关闭
    14. close(intChan)
    15. }
    16. // 从intChan取出数据,判断是否为素数,如果是,就放入到primeChan
    17. func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
    18. for {
    19. num, ok := <-intChan
    20. if !ok {
    21. break
    22. }
    23. flag := true
    24. for i := 2; i < num; i++ {
    25. if num%i == 0 {
    26. flag = false
    27. break
    28. }
    29. }
    30. if flag {
    31. //放入素数管道
    32. primeChan <- num
    33. }
    34. }
    35. fmt.Println("有一个primeNum协程因为取不到数据,退出")
    36. //这里我们还不能关闭primeChan
    37. //向exitChan写入true
    38. exitChan <- true
    39. }
    40. func main() {
    41. intChan := make(chan int, 1000)
    42. //放入结果
    43. primeChan := make(chan int, 10000)
    44. //标识退出的管道
    45. exitChan := make(chan bool, 4)
    46. start := time.Now().Unix()
    47. //开启一个协程,向intChan放入1-8000个数
    48. go putNum(intChan)
    49. //开启4个协程向intChan取出数据并判断是否为素数
    50. //如果是素数直接放入primeChan
    51. for i := 0; i < 4; i++ {
    52. go primeNum(intChan, primeChan, exitChan)
    53. }
    54. go func() {
    55. //这里主线程要进行处理
    56. for i := 0; i < 4; i++ {
    57. <-exitChan
    58. }
    59. //从exitChan取出了4个结果,可以放心的关闭primeChan
    60. end := time.Now().Unix()
    61. fmt.Println("使用协程耗时=", end-start)
    62. close(primeChan)
    63. }()
    64. //遍历primeNum,把结果取出
    65. for {
    66. res, ok := <-primeChan
    67. if !ok {
    68. break
    69. }
    70. fmt.Printf("素数=%d\n", res)
    71. }
    72. fmt.Println("main()退出")
    73. }
    1. 素数=1
    2. 素数=2
    3. 有一个primeNum协程因为取不到数据,退出
    4. 有一个primeNum协程因为取不到数据,退出
    5. 有一个primeNum协程因为取不到数据,退出
    6. 素数=3
    7. 有一个primeNum协程因为取不到数据,退出
    8. 使用协程耗时= 0
    9. 素数=5
    10. 素数=7
    11. 素数=11
    12. 素数=13
    13. 素数=17
    14. 素数=19
    15. 素数=23
    16. 素数=29
    17. 素数=31
    18. 素数=37
    19. 素数=41
    20. 素数=43
    21. 素数=47
    22. 素数=53
    23. 素数=59
    24. 素数=61
    25. 素数=67
    26. 素数=71
    27. 素数=73
    28. 素数=79
    29. 素数=83
    30. 素数=89
    31. 素数=97
    32. 素数=101
    33. 素数=103
    34. 素数=107
    35. 素数=109
    36. 素数=113
    37. 素数=127
    38. 素数=131
    39. 素数=137
    40. 素数=139
    41. 素数=149
    42. 素数=151
    43. 素数=157
    44. 素数=163
    45. 素数=167
    46. 素数=173
    47. 素数=179
    48. 素数=181
    49. 素数=191
    50. 素数=193
    51. 素数=197
    52. 素数=199
    53. main()退出

    7.使用select解决管道阻塞问题

    1. package main
    2. import (
    3. "fmt"
    4. )
    5. //使用select解决管道阻塞问题
    6. func main() {
    7. intChan := make(chan int, 10)
    8. for i := 0; i < 10; i++ {
    9. intChan <- i
    10. }
    11. stringChan := make(chan string, 5)
    12. for i := 0; i < 5; i++ {
    13. stringChan <- "hello" + fmt.Sprintf("%d", 5)
    14. }
    15. //传统的方法遍历管道,如果不关闭会阻塞,会遭遇deadlock
    16. //有可能不好确定什么时候关闭管道
    17. //使用select解决
    18. for {
    19. select {
    20. //注意:如果intChan一直没有关闭,不会一直阻塞而deadlock
    21. //会自动的到下一个case
    22. case v := <-intChan:
    23. fmt.Println("从intChan读取数据 ", v)
    24. //time.Sleep(time.Second)
    25. case v := <-stringChan:
    26. fmt.Println("从stringChan读取数据 ", v)
    27. //time.Sleep(time.Second)
    28. default:
    29. fmt.Println("都读取不到了,不玩了")
    30. return
    31. }
    32. }
    33. }

     8.goroutine中使用recover可以解决协程中出现panic

    1. package main
    2. import (
    3. "fmt"
    4. "time"
    5. )
    6. // goroutine中使用recover可以解决协程中出现panic,导致程序崩溃问题
    7. func sayHello() {
    8. for i := 0; i < 10; i++ {
    9. time.Sleep(time.Second)
    10. fmt.Println("Hello world")
    11. }
    12. }
    13. func test() {
    14. //这里我们使用defer+recover
    15. defer func() {
    16. //捕获test抛出的panic
    17. //捕获了以后,这个协程发生错误不影响其他协程
    18. if err := recover(); err != nil {
    19. fmt.Println("test() 发生错误", err)
    20. }
    21. }()
    22. //定义了一个map,让它发生错误
    23. var myMap map[int]string
    24. myMap[0] = "Golang" //error
    25. }
    26. func main() {
    27. go sayHello()
    28. //panic: assignment to entry in nil map
    29. //报错引起整个程序崩溃
    30. go test()
    31. for i := 0; i < 10; i++ {
    32. fmt.Println("main() ok=", i)
    33. time.Sleep(time.Second)
    34. }
    35. }

  • 相关阅读:
    C语言中编译时出现警告C4013(C语言不加函数原型产生的潜在错误)
    FRNet:Feature Reconstruction Network for RGB-D Indoor Scene Parsing
    适用于Linux的6个最佳Python IDE
    mybatis-plus使用sql的date_format()函数来查询数据
    PageRank算法
    从零开始搭建spring boot多模块项目
    Day4:面试必考题目
    二进制明文字符串加密:还原与反还原
    【HMS core】【FAQ】Health Kit、In-App Purchases、Account Kit典型问题合集4
    关于线程的那些事
  • 原文地址:https://blog.csdn.net/m0_46306264/article/details/132925165