5/30 go+channel并发模型 分享笔记

Channel 定义

只能使用 make 进行初始化

ch := make(chan int,0)
  • 有缓存的channel和无缓存channel

  • channel 数据操作

    1. 向channel 中添加数据
      • ch <- 数据
    2. 读取数据
      • 直接读取 接收变量 := <- ch
      • 使用 for range
            func NoCache() {
                ch := make(chan int, 10)
        
                go func(chan int) {
                    for i := 0; i < 10000; i++ {
                        ch <- i
                    }
                    close(ch)
                }(ch)
        
                // for {
                // 	data, ok := <-ch
                //  if !ok{
                //     break  
                //  }
                // 	fmt.Println(data)
                // }
        
                for v := range ch {
                    fmt.Println(v)
                }
            }
        
      • 使用 for select 多个channel时使用
  • 注意事项

    • channel数据必须有进有出
      all goroutines are asleep - deadlock!

      func mian(){
          ch := make(chan int, 10)
      
          go func(chan int) {
              for i := 0; i < 10000; i++ {
                  ch <- i
              }
              // 不添加close会报错
              close(ch)
          }(ch)
      
          for {
              data := <-ch
              fmt.Println(data)
          }
      }
      
    • 不能重复关闭同一个channel panic: close of closed channel

          ch := make(chan int)
          close(ch)
          close(ch) // panic: close of closed channel
      
    • 不能向已关闭的channel中发送数据,否则报错 panic: send on closed channel

       func NoCache() {
           ch := make(chan int, 10)
      
           go func(chan int) {
               for i := 0; i < 10000; i++ {
                   ch <- i
               }
               close(ch)
           }(ch)
      
           for v := range ch {
               fmt.Println(v)
               if v == 9900 {
                   close(ch)
               }
           }
       }
      
    • 可以从已关闭的channel中读取数据,没有数据时默认返回零值

          func ReadCloseChan() {
              ch := make(chan int)
      
              go func() {
                  for i := 0; i < 10; i++ {
                      ch <- i
                  }
                  close(ch)
              }()
      
              for {
                  // ok 判断通道是否关闭
                  data, ok := <-ch
                  if !ok {
                      fmt.Println(data, ok)
                      break
                  }
                  fmt.Println(data, ok)
              }
          }
      
  • 定时器的使用

        func Time() {
            tim := time.NewTimer(2 * time.Second)
            for {
                tim.Reset(2 * time.Second)
                <-tim.C
                fmt.Println("执行数据")
            }
        }
    
  • 并发模型

    • 一对多

          func OneToMore() {
              ch := make(chan int, 10)
      
              // 一对多模型 一个发送者多个接收者
              go func(chan int) {
                  for i := 0; i < 10000; i++ {
                      ch <- i
                  }
                  close(ch)
              }(ch)
      
              var wg sync.WaitGroup
              wg.Add(10)
              for i := 0; i < 10; i++ {
                  go func(i int, ch chan int) {
      
                      defer func() {
                          wg.Done()
                      }()
      
                      for data := range ch {
                          fmt.Printf("worker %d 执行任务 %d \n", i, data)
                      }
                  }(i, ch)
              }
      
              wg.Wait()
              fmt.Println("执行完毕")
          }
      
    • 多对一

          func MoreToOne() {
              // 多个发送者,一个接收者
              type Task struct {
                  WorkerId int
                  TaskId   int
              }
              ch := make(chan Task, 10)
              stopChan := make(chan struct{})
      
              // 多个发送者
              for i := 0; i < 10; i++ {
                  go func(i int, ch chan Task) {
                      for m := 0; m < 100; m++ {
                          ch <- Task{i, m}
                      }
      
                      // 监听关闭通知
                      <-stopChan
                  }(i, ch)
              }
      
              // 一个接收者
              tim := time.NewTimer(time.Second * 5)
      
              for {
                  var out bool = false
                  tim.Reset(5 * time.Second)
      
                  select {
                  case data := <-ch:
                      fmt.Printf("处理发送端 %d 发送过来的 %d 号任务 \n", data.WorkerId, data.TaskId)
                  case <-tim.C:
                      // 关闭通知
                      close(stopChan)
                      out = true
                  }
      
                  if out {
                      break
                  }
              }
      
              fmt.Println("任务完成")
          }
      
    • 多对多

          func MoreToMore() {
              // 多个发送者,一个接收者
              type Task struct {
                  WorkerId int
                  TaskId   int
              }
              ch := make(chan Task, 10)
              stopChan := make(chan struct{})
              warChan := make(chan struct{})
      
              // 多个发送者
              for i := 0; i < 10; i++ {
                  go func(i int, ch chan Task, war chan struct{}) {
                      var closeSwitch bool = false
      
                      for m := 0; m < 100; m++ {
      
                          // 触发关闭机制
                          if m == 80 {
                              war <- struct{}{}
                          }
      
                          select {
                          // 监控stopChannel
                          case <-stopChan:
                              closeSwitch = true
                          case ch <- Task{i, m}:
      
                          }
      
                          if closeSwitch {
                              break
                          }
                      }
                  }(i, ch, warChan)
              }
      
              // 多个接收者
              for i := 0; i < 10; i++ {
                  go func(i int, ch chan Task) {
                      var closeSwitch bool = false
                      for {
                          select {
                          case data := <-ch:
                              fmt.Printf("接收端 %d 处理发送端 %d 发送过来的 %d 号任务 \n", i, data.WorkerId, data.TaskId)
                          case <-stopChan:
                              closeSwitch = true
                          }
      
                          if closeSwitch {
                              break
                          }
                      }
      
                  }(i, ch)
              }
      
              // 创建一个监控者监听发送来的关闭信号
              go func(ch chan Task) {
                  <-warChan
      
                  close(stopChan)
              }(ch)
      
              fmt.Println("任务完成")
          }
      
posted @ 2023-05-29 10:32  GPHPER  阅读(18)  评论(0)    收藏  举报
TOP