• GO语言的高并发


    python, java c++ 采用多线程和进程变成

    多线程-每个线程占用的内存比较多,而且系统切换开销很大

    1. go语言控制主的goroutine在子协程结束后结束

    package main

    import (
    "fmt"
    "sync"
    )

    //如何解决主的goroutine在子协程结束后自动结束
    var wg sync.WaitGroup

    //WaitGroup提供了三个很有用的函数
    /*
    Add
    Done
    Wait
    Add的数量和Done的数量必须相等

    在主的协程中使用Add, Wait, 子协城中使用Done
    */
    func f(n int) {
    defer wg.Done()
    fmt.Println(n)
    }
    func main() {
    wg.Add(5)
    for i := 0; i < 5; i++ {
    go f(i)
    }
    wg.Wait()
    }

    2 互斥锁

    package main
    
    import (
       "fmt"
       "sync"
    )
    
    /*
    锁 - 资源竞争
    1. 按理说: 最后的结果应该是0
    2. 实际的情况: 1. 不是0 2. 每次的运行结果还不一样
    */
    var total int
    var wg sync.WaitGroup
    var lock sync.Mutex
    
    //互斥锁, 读写锁 同步数据 能不用锁就别用锁 - 性能
    //绝大多数的web系统来说 都是读多写少
    //有1w个人同时读数据库 A读的时候 B能读吗? 为什么要加锁呢 一定要加锁 写上和读上面加同一把锁
    //并发严重下降, B读了一个数据 造成C读了数据产生影响吗? 一定是写和读之间造成的
    //如果这边锁可以做到 读之间不会产生影响, 写和读之间才会产生影响 那多好 读写锁
    func add() {
       defer wg.Done()
       for i := 0; i < 100000; i++ {
          //先把门锁上
          lock.Lock()
          total = total + 1 //这个代码和
          lock.Unlock()
          //放开锁
          //1. 从total取出值
          //2. 将total+1
          //3. 将total+1的计算结果放入到total中
       }
    }
    
    func sub() {
       defer wg.Done()
       for i := 0; i < 100000; i++ {
          //先把门锁上
          lock.Lock()
          total = total - 1
          lock.Unlock()
          //放开锁
       }
    }
    
    func main() {
       wg.Add(2)
       go add()
       go sub()
       wg.Wait()
       fmt.Println(total)
    }

    3. 读写锁

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    /*
    锁 - 资源竞争
    1. 按理说: 最后的结果应该是0
    2. 实际的情况: 1. 不是0 2. 每次的运行结果还不一样
    */
    var total int
    var wg sync.WaitGroup
    var rwLock sync.RWMutex
    
    func read() {
        defer wg.Done()
        rwLock.RLock()
        fmt.Println("开始读取数据")
        time.Sleep(time.Second)
        fmt.Println("读取成功")
        rwLock.RUnlock()
    }
    
    func write() {
        defer wg.Done()
        rwLock.Lock()
        fmt.Println("开始修改数据")
        time.Sleep(time.Second * 10)
        fmt.Println("修改成功")
        rwLock.Unlock()
    }
    
    func main() {
        wg.Add(6)
        for i := 0; i < 5; i++ {
            go read()
        }
    
        for i := 0; i < 1; i++ {
            go write()
        }
        wg.Wait()
        fmt.Println(total)
    }

    4. go语言的channel,消息队列

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func consumer(queue chan int) {
        defer wg.Done()
        data := <-queue
        fmt.Println(data)
    }
    
    func main() {
        /*
            channel提供了一种通信机制, 定向,python java 消息队列
        */
        //    1.定义一个channel
        var msg chan int
        //    2. 初始化一个channel, 一共有两种
        msg = make(chan int)    //第一种初始化方式,无缓冲
        msg = make(chan int, 1) //第二种初始化方式,有缓冲空间的
        //    3.在go中, 使用make初始化的类型有三种, slice map channel
        msg <- 1
        wg.Add(1)
        go consumer(msg)
        wg.Wait()
    }

    以上方法只能 给一个值,取一个值,要不然就会报错

    下面为 使用for取管道中的值,及关闭管道 

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var wg sync.WaitGroup
    
    func consumer(queue chan int) {
        defer wg.Done()
        //for data := range queue{
        //    fmt.Println(data)
        //}
        for {
            data, ok := <-queue
            if !ok {
                break
            } else {
                fmt.Println(data)
                time.Sleep(time.Second)
            }
        }
    }
    
    func main() {
        /*
            channel提供了一种通信机制, 定向,python java 消息队列
        */
        //    1.定义一个channel
        var msg chan int
        //    2. 初始化一个channel, 一共有两种
        msg = make(chan int)    //第一种初始化方式,无缓冲
        msg = make(chan int, 1) //第二种初始化方式,有缓冲空间的
        //    3.在go中, 使用make初始化的类型有三种, slice map channel
        msg <- 1
        wg.Add(1)
        go consumer(msg)
        msg <- 2
        //关闭channel。1 已经关闭的channel不能在发送数据了,2 已经关闭的chanel消费者可以继续消费数据,值到数据取完为止
        close(msg)
        wg.Wait()
    }
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func consumer(msg chan int) {
        defer wg.Done()
        fmt.Println(<-msg)
    }
    
    func main() {
        var msg chan int
        msg = make(chan int)
        wg.Add(1) 
        go consumer(msg)
        msg <- 1 //当你进行 放数据到msg中的时候 这个时候会阻塞的,阻塞之前会获取一把锁, 这把锁什么时候释放 肯定是要等到数据被消费之后
        wg.Wait()
        //channel是多个goroutine之间线程安全, 如何保证的呢 使用锁?
        //如果你是没有缓冲的channel 在没有启动一个消费者之前 你放数据就会报错
        //data := <- msg
        //fmt.Println(data)
    }

    select语句

    第一种使用场景
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        /*
            go语言提供了一个select 的功能,作用于channel之上的,多路复用
            select 会随机公平的选择一个case的语句进行执行
            select 的使用场景,
                1. timeout的超时机制
        */
    
        //第一种老的方式
        //timeout := false
        //go func() {
        //    //    该goroutine如果执行时间超过了1s, 那么就会报告主的goroutine
        //    time.Sleep(time.Second * 2)
        //    timeout = true
        //}()
        //
        //for {
        //    if timeout {
        //        fmt.Println("结束")
        //        break
        //    }
        //    time.Sleep(time.Millisecond * 10)
        //}
    
        timeout := make(chan bool, 2)
        timeout2 := make(chan bool, 2)
        go func() {
            //    该goroutine如果执行时间超过了1s, 那么就会报告主的goroutine
            time.Sleep(time.Second * 2)
            timeout <- true
        }()
    
        go func() {
            //    该goroutine如果执行时间超过了1s, 那么就会报告主的goroutine
            time.Sleep(time.Second * 1)
            timeout2 <- true
        }()
    
        select {
        case <-timeout:
            fmt.Println("超时了")
    
        case <-timeout2:
            fmt.Println("超时了1")
    
        default:
            fmt.Println("继续下一次")
    
        }
    }

    示例,使用协程获取机器的CPU使用率, 在6秒后自动退出

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var wg sync.WaitGroup
    
    var stop chan bool = make(chan bool)
    
    func cpuInfo() {
        defer wg.Done()
        for {
            select {
            case <-stop:
                fmt.Println("退出CPU监控")
                return
            default:
                time.Sleep(time.Second * 2)
                fmt.Println("CPU信息读取完成")
    
            }
        }
    
    }
    func main() {
        wg.Add(1)
        go cpuInfo()
        time.Sleep(time.Second * 6)
        stop <- true
        wg.Wait()
    }

    使用context来完成上述监控

    package main
    
    import (
        "context"
        "fmt"
        "sync"
        "time"
    )
    
    var wg sync.WaitGroup
    
    func cpuInfo(ctx context.Context) {
        defer wg.Done()
        for {
            select {
            case <-ctx.Done():
                fmt.Println("退出CPU监控")
                return
            default:
                time.Sleep(time.Second * 2)
                fmt.Println("CPU信息读取完成")
    
            }
        }
    
    }
    func main() {
        wg.Add(1)
        ctx, cancel := context.WithCancel(context.Background())
        go cpuInfo(ctx)
        time.Sleep(time.Second * 6)
        cancel()
        wg.Wait()
    }

    多个调用方式

    package main
    
    import (
        "context"
        "fmt"
        "sync"
        "time"
    )
    
    var wg sync.WaitGroup
    
    func cpuInfo(ctx context.Context) {
        defer wg.Done()
        //生成一个子的context, 当父的context取消,那么父的context生成的子的context也会被取消
        ctx2, _ := context.WithCancel(ctx)
        go memoryInfo(ctx2) //在此也可调用
        //go memoryInfo(ctx)    //在此也可调用
        for {
            select {
            case <-ctx.Done():
                fmt.Println("退出CPU监控")
                return
            default:
                time.Sleep(time.Second * 2)
                fmt.Println("CPU信息读取完成")
            }
        }
    }
    func memoryInfo(ctx context.Context) {
        defer wg.Done()
        for {
            select {
            case <-ctx.Done():
                fmt.Println("退出内存监控")
                return
            default:
                time.Sleep(time.Second * 2)
                fmt.Println("内存信息读取完成")
            }
        }
    }
    
    func main() {
        wg.Add(2)
        ctx, cancel := context.WithCancel(context.Background())
        go cpuInfo(ctx)
        //go memoryInfo(ctx)
        time.Sleep(time.Second * 6)
        cancel()
        wg.Wait()
    }

    context的超时方法

    超过一定时间自动退出

    package main
    
    import (
        "context"
        "fmt"
        "sync"
        "time"
    )
    
    var wg sync.WaitGroup
    
    func cpuInfo(ctx context.Context) {
        defer wg.Done()
        for {
            select {
            case <-ctx.Done():
                fmt.Println("退出CPU监控")
                return
            default:
                time.Sleep(time.Second * 2)
                fmt.Println("CPU信息读取完成")
            }
        }
    }
    
    func main() {
        wg.Add(1)
        //ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
        ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
        go cpuInfo(ctx)
        time.Sleep(time.Second * 6)
        //cancel()
        wg.Wait()
    }






  • 相关阅读:
    Java基础——原码, 反码, 补码 详解
    为什么Java byte 类型的取值范围是-128~127
    JAVA 各种数值类型最大值和最小值 Int, short, char, long, float,&nbs
    JDK config
    为什么要设置Java环境变量(详解)
    什么是JAR包?
    如何用python将一个时间序列转化成有监督学习
    ImportError: numpy.core.multiarray failed to import
    搭建SDN网络——mininet
    回溯法解决最大团问题
  • 原文地址:https://www.cnblogs.com/wlike/p/16462636.html
Copyright © 2020-2023  润新知