《Go语言编程》学习总结4

参考书:Go语言编程

第四章  并发编程

1 Go语言支持协程goroutine

2 协程的简单例子

var counter int = 0

func Count(lock *sync.Mutex){
   lock.Lock()      // 加锁
   counter ++
   fmt.Println(counter)
   lock.Unlock()    // 解锁
}


func main(){
   lock := &sync.Mutex{}
   for i := 0;i<10;i++{
      go Count(lock)
   }
   for{
      lock.Lock()
      c := counter
      lock.Unlock()
      runtime.Gosched()
      if c >= 10{
         break
      }
   }
}

3 Go语言的通信方式channel,channel可以在两个或多个goroutine之间传递消息。

4 channel是类型相关的,一个channel只能传递一种类型的值,这个类型需要在声明channel时指定

5 channel的一般声明形式为var chanName chan  ElementType,ElementType为元素类型,如下

        var  ch  chan  int

        var  m   map[string] chan  bool

6 channel的定义也可使用make( ),如下

        ch :=  make(chan int)      // 声明并初始化了一个int类型的名为ch的channel

7 channel写入和读出

        ch  <-  value       // 将value值写入ch

        value  :=   <-  ch     // 读取ch值赋值给value

8 select语句,用于监听IO操作,当IO操作执行时会触发。每个case语句都必须是一个面向channel的操作,如下

        select {

            case <- chan1 : 

                    // 如果chan1成功读到数据则进行该case处理语句

            case chan2 <- 2 :

                    // 如果成功向chan2写入数据则进行该case处理语句

            default :

                    // 如果上面都没有执行成功则进入default处理流程

        }

9 select语句的语法

  • 每个case都必须是一个通信
  • 如果有多个case都可以运行,select会随机选择一个执行,其他的不会执行
  • 如果没有case可执行,则去执行default,如果没有default,则会阻塞,直到有个case可以执行

10 创建一个带缓冲的channel

          c :=  make(chan int , 1024)    // 创建了一个大小为1024的int类型channel,即使没有读取方,写入方也可以一直往channel里写入,在缓冲区被填完之前都不会阻塞

11 channel的超时机制,常见的是利用select机制,例如

timeout := make(chan bool,1)
go func(){
   time.Sleep(1e9)
   timeout <- true
}()
select {
case <- ch:
   fmt.Println("ch")
case <- timeout:
   fmt.Println("timeout")
}

12 单向channel变量,channel是一个原生类型,不仅支持被传递,也支持类型转换

        var  ch1 chan  int       // 不是单向channel

        var  ch2 chan<-  float64    // 单向channel,只用于写float64数据

        var  ch3 <-chan  int          //  单向channel,只用于读取int数据

        ch4 :=  make(chan int)

        ch5 := <-chan int(ch4)      // 强制转换为一个单向的读取channel

        ch6 := chan<- int(ch4)      //  强制转换为一个单向的写入channel

用法如下

        func  Parse( ch <-chan  int) {     // 限制只能读取channel

                for value := range ch {

                          fmt.Println("Parsing value :" , value)

                }

        }

13 关闭channel,用内置函数close()即可,如close(ch),如果要判断一个channel是否已经关闭,可以使用多重返回值,如下

            x , ok :=  <-ch

14 同步锁,Go语言的sync包提供了两种锁类型:sync.Mutex和sync.RWMutex。Mutex是简单的锁,当goroutine获取Mutex后其他goroutine只能等这个goroutine释放了该Mutex。RWMutex是单写多读锁,在读锁占用时会阻止写,但不阻止读,其他goroutine可以获取读锁(调用RLock())。而写锁(调用Lock())会阻止其他goroutine读和写的所有操作

15 对于这两种锁类型,任何一个Lock()或RLock()均需要保证对应有Unlock()或RUnlock()调用与之对应,否则可能导致等待该锁的所有goroutine处于饥饿状态,甚至可能导致死锁。

        var  l   sync.Mutex

        func  foo() {

                l.Lock()

                defer l.Unlock()

                // toDo

        }

16 全局唯一性操作,即只需要运行一遍代码,如全局初始化操作,Go语言提供了一个Once类型来实现

var a string
var once sync.Once

func setup(){
   a = "hello,world"
}

func doprint(){
   once.Do(setup)
   fmt.Println(a)
}

func twoprint(){
   go doprint()
   go doprint()
}

once的Do()可以保证在全局范围内只调用指定函数一次,即setup( ),而且其他goroutine在调用此语句时会先被阻塞,直至全局中once.Do( )执行完才能继续








猜你喜欢

转载自blog.csdn.net/haima95/article/details/80846139
今日推荐