Concurrency

  • 通过通信来共享而非通过共享来通信 并发模型采用 CSP communicating Seqyential process
  • goroutine 运行在相同的地址空间
  • 底层也是通过共享内存的加锁来实现 抽象级别层级更高

channel

  • channel 必须使用 make 创建并定义发送到 channel 的类型

  • cap 可以读取 channel 的缓存容量

    • ch:=make(chan int) // 定义同时规定发送到 chan 的类型
      v:=1
      ch<-v 	// 将 v 发送到 chan
      w:=<-ch	// 从 ch中读取并赋值给 w
      
  • 默认无缓存chan 接受和发送是阻塞的 除非另外一端准备好

    • value:<-c 读取会被阻塞 直到有数据接受

    • ch<-5 发送会被阻塞 直到有被读取

    • func sum(a []int, c chan int)  {
         total:=0
         for _,v:=range a{
            total+=v
         }
         c<-total
      
      }
      func main() {
         a:=[...]int {1, 2, 3,4,5,6,7,8,9,0}
         c:=make(chan int)
         go sum(a[:len(a)/2],c)
         go sum(a[len(a)/2:],c)
         x,y:=<-c,<-c
         fmt.Println(x,y,x+y)
      }
      
  • Buffer channel 带缓存的 channel

    • ch:=make(chan type,cap) 在 cap 内的读写是无阻塞的 超过 cap 时候需要等待其他 goroutine 从 channel 中读取元素 释放空间

    • for i:=rang c 可以不断读取 channel 直到 channel 被显示关闭

    • close关闭 channel 无法发送数据 但可以在消费方通过v,ok:=c;ok断言来测试是否关闭 channel

      • 在生产者方关闭 channle 在消费者方容易产生 panic
      • 结束 range 循环/无数据需要发送时候关闭 channel 才使用 close显式关闭
    • func fibonacc(n int, c chan int)  {
         x,y:=1,1
         for i:=0;i<n;i++ {
            c<-x
            x,y=y,x+y
         }
         close(c)	// 显示关闭 channel
      }
      func main() {
         c:=make(chan int, 10)
         go fibonacc(cap(c),c)
         for i:=range c {
            fmt.Println(i)
         }
      }
      
  • 多 channel 下 select

    • select 关键字监听 channel 上的数据流动

    • 默认是阻塞的 只有监听的 channel 上数据流动才运行 多个 channel 准备好时select 随机选择执行

    • 类似 switch 有 default 可设置超时来退出循环

    • func fibonacc(c, quit chan int) {
         x, y := 1, 1
         for {
            select {		// 类似 switch  监听 channel 上的数据流动
            case c <- x:
               x, y  = y, x+y
            case <-quit:
               fmt.Println("quit")
               return
            case <-time.After(5*time.Second) // 阻塞超过5 s情况
                fmpl("timeOut")
                break;
            }
         }
      }
      
      func main() {
         c := make(chan int)
         quit:=make(chan int)
         go func() {
            for i := 0; i < 10; i++ {
               fmt.Println(<-c)
            }
            quit<-0
         }()
         fibonacc(c,quit)
      }
      
    channel 通信
    func testAppendA(t *testing.T) {
       x := []int{1, 2, 3}
       appendA(x)
       fmt.Printf("main %v\n", x)
    }
    
    func appendA(x []int) {
       x[0] = 100
       fmt.Printf("appendA %v\n", x)
    }
    func main() {
       ch := make(chan struct{})
    
       go func() {
          for i := 1; i < 11; i++ {
             ch <- struct{}{}
             if i%2 == 1 {
                fmt.Println("奇数", i)
             }
          }
       }()
       go func() {
          for i := 0; i < 11; i++ {
             <-ch
             if i%2 == 0 {
                fmt.Println("偶数", i)
             }
          }
       }()
       time.Sleep(10 * time.Second)
    }
    
广播通信
func main() {
   notify := make(chan struct{})

   for i := 0; i < 10; i++ {
      go func(i int) {
         for {
            select {
            case <-notify:
               fmt.Println("done...", i)
            case <-time.After(1 * time.Second):
               fmt.Println("wait notify", i)
            }
         }
      }(i)
   }
   time.Sleep(1 * time.Second)
   close(notify)
   time.Sleep(3 * time.Second)
}
  • Goexit
    • 退出当前 Goroutine 但defer 仍调用
  • Gosched
    • 让出 goRoutine 权限
  • NumCPU NumGoroutine
    • 返回 cpu数目
    • 返回执行和排队的任务总数
  • GOMAXPROCS
    • 并行计算的 cpu 核数最大值 返回之前的核数值