10.Go-goroutine,waitgroup,互斥锁和channel

10.1.goroutine

goroutine的使用

//Learn_Go/main.go
package main

import (
    "fmt"
    "time"
)

func demo(count int)  {
    for i :=1; i < 10; i++{
        fmt.Println(count,":",i)
    }
}

func main() {
    for i :=1; i < 10; i++{
        go demo(i)
    }
    //添加休眠时间等待goroutine执行结束
    time.Sleep(3e9)
}

10.2.waitgroup

WaitGroup直译为等待组,其实就是计数器,只要计数器中有内容将一直阻塞
WaitGroup有三种方法

  • Add(delta int)表示向内部计数器添加增量(delta),其中参数delta可以使负数
  • Done() 表示减少waitgroup计数器的值,应当在程序最后执行,相当于Add(-1)
  • Wait()  表示阻塞知道waitgroup计数器为0
//Learn_Go/main.go
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(5)
    for i := 0; i < 5; i++{
        go func(j int) {
            fmt.Println("第",j,"次执行")
            wg.Done()
        }(i)
    }
    wg.Wait()
    fmt.Println("程序结束")
}

10.3.互斥锁和读写锁

(1)互斥锁
可以使用sync.Mutex对内容加锁,互斥锁的使用场景

  • 多个gouroutine访问同一个函数代码段
  • 操作一个全局变量
  • 为了保证共享变量安全性,值安全性

(2)读写锁
Go语言中的map不是线程安全的,多个gouroutine同时操作会出现错误
RWMutex可以添加多个读锁或者一个写锁,读写锁不能同时存在
map在并发下读写就需要结合读写锁完成
互斥锁表示锁的代码同一时间只能有一个goroutine运行,而读写锁表示在锁范围内数据的读写操作

//Learn_Go/main.go
package main

import (
    "fmt"
    "sync"
)

func main() {
    var rwm sync.RWMutex
    var wg sync.WaitGroup
    wg.Add(10)
    m := make(map[int]int)
    for i := 0; i < 10; i++{
        go func(j int) {
            rwm.Lock()
            m[j] = j
            fmt.Println(m)
            rwm.Unlock()
            wg.Done()
        }(i)
    }
    wg.Wait()
    fmt.Println("程序结束")
}

10.4.channel

channel是进程内通信方式,每个channel只能传递一个类型的值,这个类型需要在声明channel时指定
channel在Go中主要的两个作用:同步和通信
(1)声明channel的语法

  • var 名称 chan 类型
  • var 名称 chan <- 类型       只写
  • var 名称 <- chan 类型       只读
  • 名称 := make(chan int)      无缓存chanel
  • 名称 := make(chan int)      无缓存channel
  • 名称 := make(chan int,100)     有缓存channel

(2)操作channel的语法

  • ch <- 值          向ch中添加一个值
  • <- ch               从ch中取出一个值
  • a := <-ch         从ch中取出一个值并赋值给a
  • a,b := <-ch       从ch中取出一个值赋值给a,如果ch已经关闭或ch中没有值,b为false,

(3)无论是向channel存数据还是取数据都会阻塞

//Learn_Go/main.go
package main

import "fmt"

func main() {
    ch := make(chan int)
    go func() {
        fmt.Println("执行")
        ch <- 111     
    }()
    a := <- ch
    fmt.Println(a)
    fmt.Println("程序结束")
}

(4)使用channel实现gouroutine之间通信

//Learn_Go/main.go
package main

import "fmt"

func main() {
    ch1 := make(chan string)
    ch2 := make(chan int)

    go func() {
        ch1 <- "derek"
        ch2 <- 111
    }()

    go func() {
        content := <- ch1
        fmt.Println("取出数据:",content)       //取出数据: derek
        ch2 <- 222
    }()

    a := <- ch2
    b := <- ch2
    fmt.Println(a,b)              //111 222
    fmt.Println("程序结束")
}

(5)可以使用for range获取channel中内容

//Learn_Go/main.go
package main

import "fmt"

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        for i := 0; i<10;i++{
            ch1 <- i
        }
        ch2 <- 222
    }()

    go func() {
        for n := range ch1{
            fmt.Println(n)
        }
    }()
    <- ch2
    fmt.Println("程序结束")
}