设为首页 加入收藏

TOP

golang基础--Gocurrency并发(一)
2018-10-19 15:51:12 】 浏览:87
Tags:golang 基础 --Gocurrency 并发

Go并发特点

  • goroutine只是由官方实现的超级"线程池"而已,每个实例4-5kb的栈内存占用和用于实现机制而大幅减少的创建和销毁开销。

  • 并发不是并行(多CPU): Concurrency Is Not Parallelism

  • 并发主要由切换时间片来实现"同时"运行,并行则是直接利用多核实现多线程的运行,但Go可以设置使用核数,以发挥多核计算机的能力。
    • 通过go关键字实现多线程
    package main
    import (
        "fmt"
        "time"
    )
    
    func Go() {
        fmt.Println("1234...") 
    
    }
    
    func main() {
        go Go()                //go关键字构成多线程
        time.Sleep(2 * time.Second) //主程序睡眠2s
    }
  • Goroutine 奉行通过通信来共享内存,而不是共享内存来通信

Channel

  • Channel是goroutine沟通的桥梁,大都是阻塞同步的
  • 通过make创建,close关闭(当程序简单时,回自动关闭)

    package main
    import  "fmt"
    
    func main() {                        //主程序
        c := make(chan bool)           //初始化一个chan类型
        go func() {                 //子程序
            fmt.Println("123...")      //执行主程序
            c <- true                       //通过<-存入bool类型到chan中
        }()
    fmt.Println(1)                  //程序执行步骤:1st
    read_chan := <-c                         //<-c 从chan中读取bool,程序执行步骤:2nd
    fmt.Println(read_chan)                 //程序执行步骤:3rd
    }
    
    /*output
    1st     1           
    2nd     123...
    3rd     true
    */

    注意以上程序的执行顺序(channel无缓存时):先执行读取操作c<-c,因为channel中没有值,所以程序发生阻塞,此时执行chanel写操作,然后再执行读操作。

  • Channel是引用类型

  • 可以使用for range来迭代不断操作channel

    package main
    import  "fmt"
    
    func main() {
        c := make(chan bool)       //初始化一个chan类型
        go func() {                        //go结合匿名函数,构造并发
            fmt.Println("123...")     //执行主程序
            c <- true                     //通过<-存入bool类型到chan中
            close(c)                      //关闭通道:必须明确在哪个地方关闭
        }()
    
        for v := range c {       //for循环chanel
        }
    }
    
    /*output
        123...
        true
    */
  • 可以设置单向(读&写)或双向通道--默认是双向通道

  • 可以设置缓存大小(默认为0,阻塞),在未被填充前不会发生阻塞(异步),比如缓存20个,可以同时进行20个读操作或者写操作,注意读的操作先于写的操作

    package main
    import (
        "fmt"
    )
    
    func main() {                                       //主程序
        c := make(chan bool, 1)             //初始化一个chan类型,缓存为2
        go func() {                                  //子程序
            fmt.Println("123...")            //执行主程序,执行步骤:2
            c <- true                            //写操作,执行步骤:2
        }()
        fmt.Println(2)                             //执行步骤:1
        fmt.Println(123, <-c)                 //读操作,执行步骤:2
        fmt.Println(3)                            //执行步骤:3
    }
    
    /*output
    1   2
    2   123...
    2   123 true
    3   3
    */
  • 并行并发,利用多核CPU,当使用单线程执行的时候,就是同步按部就班的执行程序,使用多核时,且没有设置channel缓存机制时是随机异步发生的。但是这样就会造成一个问题,因为是随机的,所以CPU在选择的时候,某有一个程序并没有执行,会造成程序执行的遗漏。

    package main
    import (
        "fmt"
        "runtime"
    )
    
    func main() {                                                                        //主程序
        runtime.GOMAXPROCS(runtime.NumCPU())              //获取CPU的核数
        c := make(chan bool)                                                  //创建channel
        for i := 0; i < 10; i++ {                                                  //启动10次
            go Go(c, i)
        }
        <-c                                                                             //读取chanel值
    }
    
    func Go(c chan bool, index int) {
        a := 1
        for i := 0; i < 1000000; i++ {
            a += i
        }
        fmt.Println(index, a)
    
        if index == 9 {
            c <- true //向chanel传入值
        }
    }
    
    /*output
    4 499999500001
    9 499999500001
    */
  • 解决异步并发数据丢失:方式1:根据并发执行次数为channel设置同等数量的缓存机制。

    package main
    
    import (
        "fmt"
        "runtime"
    )
    
    func main() {                                                             //主程序
        runtime.GOMAXPROCS(runtime.NumCPU())   //获取CPU的核数
        c := make(chan bool, 10)                                //创建channel
        for i := 0; i < 10; i++ {                                      //启动10次
            go Go(c, i)
        }
        for i := 0; i < 10; i++ {                                      //for 循环为chan循环读取十次
            <-c                                                         //读取chanel值
        }
    }
    
    func Go(c chan bool, index int) {
        a := 1
        for i := 0; i < 1000000; i++ {
            a += i
        }
        fmt.Println(index, a)
    
        c <- true                                           //向chanel传入值
    
    }
    
    /*output
        0 499999500001
        9 499999500001
        1 499999500001
        5 499999500001
        6 499999500001
        2 499999500001
        7 499999500001
        3 499999500001
        8 499999500001
        4 499999500001
    */
  • 解决方法2:使用同步 sync 包, sync.WaitGroup{} 创建任务池;sync.add(n)为任务池添加任务个数; sync.Wait()主程序等待(守护进程); sync.Done()子进程全部执行完毕告知主进程,退出程序。

    package main
    import (
        "fmt"
        "runtime"
        "sync"
    )
    
    func main() { //主程序
        runtime.GOMAXPROCS(runtime.NumCPU()) //获取CPU的核数
        wg := sync.WaitGroup{}               //调用同步方法,类似一个池子
        wg.Add(10)                           //增加10个任务数
        for i := 0;
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇linux /mac 下 go环境变量配置 下一篇Go 跨域请求问题

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目