【问题标题】:Is map[string] chan thread safe?map[string] chan 线程安全吗?
【发布时间】:2022-01-22 14:00:19
【问题描述】:

感谢您在这个问题上帮助我。

据我所知,在 golang 中 map 是非线程安全的,但 chan 是线程安全的。但是如果我使用 chan 作为 map 的值呢?这个map 会成为线程安全的吗?

我写了一个简单的测试(不知道这是否是正确的证明方法)如下所示,并在没有concurrent map read/write error的情况下运行它大约30次。这是否意味着线程安全chan使非-线程安全map线程安全?

map 是否成为线程安全的,谁能为我解释得更深入一点?谢谢!

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().Unix())
    te := &testS{
        name: "test",
        val: map[string]chan int{
            "a": make(chan int, 10000000),
        },
    }

    for i := 0; i < 50000; i++ {
        te.val["a"] <- i
    }

    for i := 0; i < 30000; i++ {
        go write(te)
        go read(te)
    }
    for {
        fmt.Println("Waiting")
        time.Sleep(time.Second)
    }
}

func read(t *testS) {
    time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
    <-t.val["a"]
    fmt.Println("read")
}

func write(t *testS) {
    time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
    t.val["a"] <- 1
    fmt.Println("write")
}

type testS struct {
    name string
    val  map[string]chan int
}

【问题讨论】:

  • "但是如果我使用 chan 作为映射的值呢?这个映射会成为线程安全的吗?" -- 不会。
  • 请注意,只读映射对于并发使用是安全的,无论元素类型如何。您上面的示例仅从地图中读取。因此不会发生数据竞争错误。

标签: dictionary go concurrency thread-safety channel


【解决方案1】:

我想我已经解决了这个问题。 正如@mkopriva 所说,这个例子实际上从未写信给map。但是这个例子也可以帮助我理解这个问题:

chan的读/写实际上不会影响map,你可以认为map正在存储频道的地址,只有当你删除或添加一些东西到map时你才会写信给它。对 `chann` 的读/写不会影响其地址,因此不会“写”到地图。

一句话:读/写chan与读/写map无关

我还有另一个测试来证明这一点:

test := map[string]chan int{
        "a": make(chan int, 1000),
    }

    for i := 0; i < 200; i++ {
        test["a"] <- i
    }

    go func() {
        for {
            fmt.Printf("get from chan: %d\n", <-test["a"])
            time.Sleep(time.Second)
        }
    }()

    time.Sleep(5 * time.Second)
    newChan := make(chan int, 1000)
    for i := 200; i > 0; i-- {
        newChan <- i
    }
    test["a"] = newChan
    for {
        fmt.Println("waiting")
        time.Sleep(time.Second)
    }

你会看到将test["a"]改为newChan后,输出会开始打印newChan中的元素

【讨论】:

  • 只是补充一下,对于并发安全映射,您应该使用sync.Map
  • 谢谢,顺便说一句,sync.Mapstructmapsync.Mutex 之间有什么不同吗?我想如果我必须存储其他信息而不仅仅是map,我应该使用structsync.Mutex
  • 是的,对于高度并行的应用程序,使用sync.Map 作为您的商店是不错的选择。 IE:作为sync.Map 的键的唯一键和指向您的结构的指针。
猜你喜欢
  • 2020-08-24
  • 1970-01-01
  • 2013-02-10
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
  • 2011-01-24
  • 2023-01-11
相关资源
最近更新 更多