Go语言并发之并发实现、多核CPU设置、多协程间的通信、select、多协程间的同步
目录结构

├── gorotine
│    └── gorotine.go
└── main.go

  • 并发实现:协程

    • 启动协程(加go关键字)

gorotine.go文件

     package gorotine
     import (
         "fmt"
         "time"
     )
     func Loop()  {
         for i:=1;i<11;i++ {
             //防止程序运行太快,看不到是否为并发执行,这里暂停10微秒
             time.Sleep(time.Microsecond * 10)
             fmt.Printf("%d,",i)
         }
     }   

main.go文件

    package main
    import (
        "./gorotine"
        "time"
    )
    func main() {
        //调用2次,串行执行
        //gorotine.Loop()
        //gorotine.Loop()
        //运行结果:1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,
    
        //并发,并发执行
        go gorotine.Loop()
        go gorotine.Loop()
        //防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
        time.Sleep(time.Second * 5)
        //运行结果:1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,
    }
  • 多核CPU设置
    package main
    import (
        "./gorotine"
        "fmt"
        "runtime"
        "time"
    )
    func main() {
        //调用2次,串行执行
        //gorotine.Loop()
        //gorotine.Loop()
        //运行结果:1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,
    
        //并发,并发执行
        fmt.Printf("cup num = %d", runtime.NumCPU())  // cup num = 12
        fmt.Print("\n")
        runtime.GOMAXPROCS(runtime.NumCPU() - 1)   //限制go程序的运行核心数,一般总核心数减一
        go gorotine.Loop()  // 加go关键字即可实现协程
        go gorotine.Loop()
        //防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
        time.Sleep(time.Second * 5)
        //运行结果:1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,
    }
  • 多协程间的通信

    • channel(管道)

gorotine.go文件

    package gorotine
    
    import (
        "fmt"
        "time"
    )
    var chanInt chan int = make(chan int, 10) //创建缓存为10的管道
    
    func Send()  {//向管道发送数据
        time.Sleep(time.Second * 1)
        chanInt <- 1
        time.Sleep(time.Second * 1)
        chanInt <- 2
        time.Sleep(time.Second * 1)
        chanInt <- 3
    }
    
    func Receive()  {//获取管道数据
        num := <- chanInt
        fmt.Println("num:", num)
        fmt.Print("\n")
        num = <- chanInt
        fmt.Println("num:", num)
        fmt.Print("\n")
        num = <- chanInt
        fmt.Println("num:", num)
    }

main.go文件

    package main
    
    import (
        "./gorotine"
        "time"
    )
    
    func main() {
        go gorotine.Send()     //启动发送数据的协程
        go gorotine.Receive()  //启动接收数据的协程
        //防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
        time.Sleep(time.Second * 5)
        //结果:
        /*
        num: 1
        num: 2
        num: 3
        */
    }
  • select

gorotine.go文件

    package gorotine
    
    import (
        "fmt"
        "time"
    )
    var chanInt chan int = make(chan int, 10) //创建缓存为10的管道
    var timeout chan bool = make(chan bool) //创建管道
    
    func Send()  {//向管道发送数据
        time.Sleep(time.Second * 1)
        chanInt <- 1
        time.Sleep(time.Second * 1)
        chanInt <- 2
        time.Sleep(time.Second * 1)
        chanInt <- 3
        time.Sleep(time.Second * 2)
        timeout <- true
    }
    
    func Receive()  {//获取管道数据,同时读取两个文件
        for  {
            select {
            case num:=<-chanInt:
                fmt.Println("num:", num)
            case <-timeout:
                 fmt.Println("timeout...")
            }
        }
        //应用场景:十个协程读10个不同文件数据往一个协程向文件写数据
    }

main.go文件

    package main
    
    import (
        "./gorotine"
        "time"
    )
    
    func main() {
        go gorotine.Send()     //启动发送数据的协程
        go gorotine.Receive()  //启动接收数据的协程
        //防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
        time.Sleep(time.Second * 5)
        //结果:
        /*
        num: 1
        num: 2
        num: 3
        timeout...
        */
    }
  • 多协程间的同步(多个协程读取不同文件,写文件的协程把读出来的数据完成后再进行别的操作)

    • 系统工具sync.waitgroup

      • Add(delta int ) 添加携程记录
      • Done() 移除协程记录
      • Wait() 同步等待所有记录的协程全部结束

gorotine.go文件

    package gorotine
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var WG sync.WaitGroup
    //读取数据
    func Read()  {
        for i:=0;i<3;i++ {
            WG.Add(1)   //添加携程记录
        }
    }
    //写入数据
    func Write()  {
        for i:=0;i<3;i++ {
            time.Sleep(time.Second * 2)
            fmt.Println("Done ->", i)
            WG.Done()      //移除协程记录
        }
    }

main.go文件

    package main
    
    import (
        "fmt"
        "time"
        "./gorotine"
    )
    
    func main() {
        gorotine.Read()
        go gorotine.Write()
        gorotine.WG.Wait()
        fmt.Println(" All done!")
        //结果:
        /*
        Done -> 0
        Done -> 1
        Done -> 2
        All done!
        */
    
        time.Sleep(time.Second * 5)
    }

下面是拓展(对上面的代码合并一下):

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var wg sync.WaitGroup
    
    var arr = []int{1,2,3}
    
    func main() {
        for _,val:=range arr{
            wg.Add(1) //添加携程记录
            go func(val int) {
                time.Sleep(time.Second * 10)
                fmt.Println("Done ->", val)//执行后续程
                defer wg.Done()
            }(val)
        }
        wg.Wait() //移除协程记录
        fmt.Println(" All done!")  //执行后续程序
    }
Last modification:September 23, 2020
如果觉得我的文章对你有用,请随意赞赏