5_Concurrency

  • (1) goroutine是一个被Go运行时管理的轻量级线程

      go f(x, y, z)
    

    f, x, y, and z在当前goroutine发生,f函数的执行在新的goroutine发生

    (2) Goroutine在同一块地址空间运行,所以共享内存时需要同步

  • channels

    (1) Channels是一种__管道__,可以通过channels来发送和接收变量值,使用 __<-__运算符

      ch <- v    // Send v to channel ch
      v := <-ch  // Receive from ch, and assign value to v
    

    (2) 和map和slice一样,channel也需要先声明

      ch := make(chan int)        //channel
    
      sl := make([]int, 5)        //slice
    
      m := make(map[string]int)   //map
    

    (3) 在经由channel发送或接收时,必须另一方准备好以后才开始发送/接收,否则就会Block

    这提供了__同步__的一种方法

      package main
    
      import "fmt"
    
      func sum(s []int, c chan int) {
    
          sum := 0
    
          for _, v := range s {
              sum += v
          }
    
          c <- sum // send sum to c
      }
    
      func main() {
    
          s := []int{7, 2, 8, -9, 4, 0}
    
          c := make(chan int)
    
          go sum(s[:len(s)/2], c)
          go sum(s[len(s)/2:], c)
    
          x, y := <-c, <-c // receive from c
    
          fmt.Println(x, y, x+y)
      }
    

    (4) 带__buffer__的channel

    在创建时指定buffer数量

      ch := make(chan int, 2)
    

    当buffer已满时,会阻塞发送方;当buffer已空时,会阻塞取回方。如果只有一个线程会被报死锁错误

      package main
    
      import "fmt"
    
      func main() {
    
          ch := make(chan int, 2)
    
          ch <- 1
          ch <- 2
    
          fmt.Println(<-ch)
          fmt.Println(<-ch)
      }
    

    (5) 用

      v, ok := <-ch
    

    可以判断channel是否关闭

    (6) 用

      for i := range c
    

    可以反复从channel获取值,直到channel关闭

    (7) 只有发送方可以关闭channel

      close(c)
    

    但是事实上关闭channel的操作不是必须的(和关闭文件不一样),只有提示接收方终止循环时关闭channel才有必要

      package main
    
      import (
          "fmt"
      )
    
      func fibonacci(n int, c chan int) {
    
          x, y := 0, 1
    
          for i := 0; i < n; i++ {
    
              c <- x
              x, y = y, x+y
          }
    
          close(c)
      }
    
      func main() {
    
          c := make(chan int, 10)
    
          go fibonacci(cap(c), c)
    
          for i := range c {
              fmt.Println(i)
          }
      }
    
  • select语句

    (1) select阻塞直到select块中的某个case可以运行。如果多个case都可以运行,那就随机选一个

      package main
    
      import "fmt"
    
      func fibonacci(c, quit chan int) {
    
          x, y := 0, 1
    
          for {
    
              select {
                  case c <- x:
      	            x, y = y, x+y
                  case <-quit:
      	            fmt.Println("quit")
      	            return
              }
          }
      }
    
      func main() {
    
          c := make(chan int)
          quit := make(chan int)
    
          go func() {
              for i := 0; i < 10; i++ {
      	        fmt.Println(<-c)
              }
    
              quit <- 0
          }()
    
          fibonacci(c, quit)
      }
    

    (2) 如果select块中有default,那么当其他的case都不是ready状态时,执行default块中的内容

      package main
    
      import (
          "fmt"
          "time"
      )
    
      func main() {
    
          tick := time.Tick(100 * time.Millisecond)
          boom := time.After(500 * time.Millisecond)
    
          for {
              select {
              case <-tick:
      	        fmt.Println("tick.")
              case <-boom:
      	        fmt.Println("BOOM!")
      	        return
              default:
      	        fmt.Println("    .")
      	        time.Sleep(50 * time.Millisecond)
              }
          }
      }
    
  • sync.Mutex

    (1) 当我们只需要确保互斥访问变量值,不需要用channel沟通时,可以考虑使用sync.Mutex

    (2) sync.Mutex有两个方法

      Lock
      Unlock
    

    有一个小技巧是使用__defer__确保unlock()操作一定执行

      package main
    
      import (
          "fmt"
          "sync"
          "time"
      )
    
      // SafeCounter is safe to use concurrently.
      type SafeCounter struct {
          v   map[string]int
          mux sync.Mutex
      }
    
      // Inc increments the counter for the given key.
      func (c *SafeCounter) Inc(key string) {
          c.mux.Lock()
          // Lock so only one goroutine at a time can access the map c.v.
          c.v[key]++
          c.mux.Unlock()
      }
    
      // Value returns the current value of the counter for the given key.
      func (c *SafeCounter) Value(key string) int {
          c.mux.Lock()
          // Lock so only one goroutine at a time can access the map c.v.
          defer c.mux.Unlock()   //这里用defer很巧妙
          return c.v[key]
      }
    
      func main() {
    
          c := SafeCounter{v: make(map[string]int)}
          for i := 0; i < 1000; i++ {
              go c.Inc("somekey")
          }
    
          time.Sleep(time.Second)
          fmt.Println(c.Value("somekey"))
      }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值