如何在程序运行时安全地交换内存映射?

时间:2018-02-01 21:16:58

标签: go concurrency

我有一个go服务运行,在内存中有一个地图,比如map1。地图数据(键和值)依赖于存储在S3中的文件。 goroutine正在运行以监视此文件,如果有更改,则下载文件,解析文件并创建新映射,例如map2。如何在不导致其他线程读取不一致数据的情况下将map1的内容与map2交换?

下面我粗略地了解了我是如何考虑解决这个问题的。以下程序的输出是" map1-a"的序列,后面是" map2-a"的序列。地图被交换了。这是最好的方法吗?

package main

import (
    "fmt"
    "time"
)

func initializeAndMonitor() *map[string]string {
    map1 := make(map[string]string)
    map1["a"] = "map1-a"
    go func() {
        time.Sleep(5 * time.Second)
        map2 := make(map[string]string)
        map2["a"] = "map2-a"
        map1 = map2
    }()
    return &map1
}


func main() {
    map1 := initializeAndMonitor()
    for count := 0; count < 100; count = count + 1 {
        fmt.Println((*map1)["a"])
        time.Sleep(1 * time.Second)
    }
}

1 个答案:

答案 0 :(得分:2)

这是互斥的目的;将读取和写入包装在sync.RWMutex

package main

import (
    "fmt"
    "time"
    "sync"
)

var mu = sync.RWMutex{}

func initializeAndMonitor() *map[string]string {
    map1 := make(map[string]string)
    map1["a"] = "map1-a"
    go func() {
        mu.Lock()
        defer mu.Unlock()
        time.Sleep(5 * time.Second)
        map2 := make(map[string]string)
        map2["a"] = "map2-a"
        map1 = map2
    }()
    return &map1
}


func main() {
    map1 := initializeAndMonitor()
    for count := 0; count < 100; count = count + 1 {
        mu.RLock()
        fmt.Println((*map1)["a"])
        mu.RUnlock()
        time.Sleep(1 * time.Second)
    }
}