zoukankan      html  css  js  c++  java
  • Go语言-如何保证slice的协程安全

    发现问题

    今天在看代码的时候,遇见了多个协程写同一个slice的情况,发现未对slice做任何保护,亦未使用其他手段保证并发安全,这样肯定会出错的。

    思考

    slice不是协程安全的,所以在多个协程中读写slice是不安全的,在高并发的情况下会产生不可控制的错误。

    总结

    这里记录一下错误的使用方式与正确的使用方式:

    错误的使用方式:

    var a []int
    
    for i := 0; i < 10000; i++ {
        go func() {
            a = append(a, 1) // 多协程并发读写slice
        }()
    }
    
    fmt.Println(len(a))

    输出结果可能不等于期望的值

    正确对方式

    第一种方式:

    对slice加锁,进行保护

       num := 10000
    
        var a []int
        var l sync.Mutex
    
        var wg sync.WaitGroup
        wg.Add(num)
    
        for i := 0; i < num; i++ {
            go func() {
                l.Lock() // 加锁
                a = append(a, 1)
                l.Unlock() // 解锁
                wg.Done()
            }()
        }
    
        wg.Wait()
    
        fmt.Println(len(a))

    缺点:锁会影响性能

    第二种方式:

    使用channel的传递数据

        num := 10000
    
        var wg sync.WaitGroup
        wg.Add(num)
    
        c := make(chan int)
        for i := 0; i < num; i++ {
            go func() {
                c <- 1 // channl是协程安全的
                wg.Done()
            }()
        }
    
        // 等待关闭channel
        go func() {
            wg.Wait()
            close(c)
        }()
    
        // 读取数据
        var a []int
        for i := range c {
            a = append(a, i)
        }
    
        fmt.Println(len(a))

    第三种方式:

    使用索引

        num := 10000
    
        a := make([]int, num, num)
    
        var wg sync.WaitGroup
        wg.Add(num)
    
        for i := 0; i < num; i++ {
            i := i // 必须使用局部变量
            go func() {
                a[i] = 1
                wg.Done()
            }()
        }
    
        wg.Wait()
    
        count := 0
        for i := range a {
            if a[i] != 0 {
                count++
            }
        }
        fmt.Println(count)

    优点:无锁,不影响性能

  • 相关阅读:
    Android 视图切换库的使用
    Ext3.4--TreeGridDemo
    Extjs不错的博客
    Extjs学习笔记--(六,选择器)
    Webservice简单案例
    Extjs学习笔记--(五,事件)
    Extjs学习笔记--(四,基本函数介绍)
    Extjs学习笔记--(三,调试技巧)
    SQL集合运算:差集、交集、并集
    Extjs学习笔记--(二)
  • 原文地址:https://www.cnblogs.com/zcqkk/p/11772173.html
Copyright © 2011-2022 走看看