首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sync.Map似乎不安全,并发读写

sync.Map似乎不安全,并发读写
EN

Stack Overflow用户
提问于 2021-03-24 02:28:36
回答 2查看 2.2K关注 0票数 0

在金刚标准包中测试sync.Map。同时读和写似乎不安全。怎么了?

测试代码:

代码语言:javascript
复制
package main

import (
    "log"
    "sync"
)

func main() {
    var m sync.Map
    m.Store("count", 0)

    var wg sync.WaitGroup

    for numOfThread := 0; numOfThread < 10; numOfThread++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for i := 0; i < 1000; i++ {
                value, ok := m.Load("count")
                if !ok {
                    log.Println("load count error")
                } else {
                    v, _ := value.(int)
                    m.Store("count", v+1)
                }
            }
        }()
    }

    log.Println("threads starts")
    wg.Wait()

    value, ok := m.Load("count")
    if ok {
        v, _ := value.(int)
        log.Printf("final count: %d", v)
    }

    log.Println("all done")
}

https://play.golang.org/p/E-pw4iZUceB

结果应该是10000,但得到的是随机数,而不是10000:

代码语言:javascript
复制
2009/11/10 23:00:00 threads starts
2009/11/10 23:00:00 final count: 6696
2009/11/10 23:00:00 all done
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-03-24 02:33:15

你有一个种族状况:

代码语言:javascript
复制
 value, ok := m.Load("count")
 ...
 v, _ := value.(int)
 m.Store("count", v+1)

上面的读-修改-存储不会保护其他的goroutines做同样的事情,因此其他goroutines执行的一些增量将被忽略。

sync.Map保护对其成员的并发访问。这意味着,对地图的写入不会导致其他人读取不一致的地图。如果你读-修改-写,没有什么能保护其他猩猩在同一时间更新这个值。当您读取-修改-更新时,您需要一个互斥以保护对地图的访问。

票数 3
EN

Stack Overflow用户

发布于 2021-03-24 03:12:20

代码语言:javascript
复制
package main

import (
    "log"
    "sync"
)

func main() {
    var m sync.Map
    m.Store("count", 0)

    var wg sync.WaitGroup
    var mu *sync.Mutex

    for numOfThread := 0; numOfThread < 10; numOfThread++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for i := 0; i < 1000; i++ {
                mu.Lock()
                value, ok := m.Load("count")
                if !ok {
                    log.Println("load count error")
                } else {
                    v, _ := value.(int)
                    m.Store("count", v+1)
                }
               mu.Unlock()
            }
        }()
    }

    log.Println("threads starts")
    wg.Wait()

    value, ok := m.Load("count")
    if ok {
        v, _ := value.(int)
        log.Printf("final count: %d", v)
    }

    log.Println("all done")
}

读和写操作都是线程安全的,但是您正在尝试一个upsert或read+write操作。它不是线程安全的。修改代码,使其线程安全。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66773922

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档