如果键始终是唯一的,那么在并发写入 Golang map 是否安全?

huangapple go评论153阅读模式
英文:

Is it safe to write to a Golang map concurrently if the keys are always unique?

问题

上面的代码是否安全可用?请注意,多个字符串将同时写入映射m,但它们肯定是唯一的值,因此没有字符串会被写入超过一次。

英文:
package main

import (
    "sync"
    "fmt"
)

var m = make(map[string]string)

var seen = make(map[string]bool)

func main() {
    wg := new(sync.WaitGroup)
    wg.Add(1)
    ch := make(chan string)
    go deduplicate(ch, wg)

    toAdd := []string{"foo", "bar", "baz", "foo"}
    for _, s := range toAdd {
        ch <- s
    }
    wg.Wait()
    fmt.Println(m)
}

func deduplicate(ch chan string, wg *sync.WaitGroup) {
    for s := range ch {
        if seen
展开收缩
{ wg.Done() continue } seen
展开收缩
= true go write(s) } } func write(s string) { m
展开收缩
= "written" }

Is the code above safe to use? Note that multiple strings will be written to the map m concurrently, but they are sure to be unique values, so no string will be written more than once.

答案1

得分: 4

不,那是不安全的。无论密钥是否唯一,都需要避免并发写入或与读取并发的写入。并发读取是可以的。

您可以使用竞争检测器通过运行go run -race myprog.go来查找此类问题。请参阅https://golang.org/doc/articles/race_detector.html。

英文:

No, that is not safe. It doesn't matter if the keys are unique. You need to avoid concurrent writes or writes concurrent with reads. Concurrent reads are OK.

You can use the race detector to find problems like this by running go run -race myprog.go. See https://golang.org/doc/articles/race_detector.html.

答案2

得分: 1

这是一个Go语言程序的输出结果,它显示了数据竞争(data race)的警告信息。数据竞争是指多个goroutine并发访问共享数据,并且至少有一个goroutine对该数据进行了写操作,而没有进行同步保护。数据竞争可能导致程序的行为不确定,因此需要修复这些问题。

警告信息中显示了多个goroutine对同一个内存地址进行了写操作,以及一个goroutine对同一个内存地址进行了读操作。这些操作发生在程序的不同部分,可能导致数据竞争。

为了解决数据竞争问题,可以使用Go语言提供的同步机制,如互斥锁(mutex)或通道(channel),来保护共享数据的访问。通过在并发访问共享数据之前获取锁,并在访问完成后释放锁,可以确保同一时间只有一个goroutine能够访问共享数据,从而避免数据竞争。

在这个例子中,你可以检查程序中的racer.go文件的第38行,看看是否有对共享数据的并发访问,并使用适当的同步机制来修复数据竞争问题。

英文:

It is not safe. Go maps are are self-organizing data structures. Run the race detector.

$ go run -race racer.go
==================
WARNING: DATA RACE
Write at 0x00c42007c150 by goroutine 8:
  runtime.mapassign_faststr()
      /home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
  main.write()
      /home/peter/gopath/src/racer.go:38 +0x6e

Previous write at 0x00c42007c150 by goroutine 7:
  runtime.mapassign_faststr()
      /home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
  main.write()
      /home/peter/gopath/src/racer.go:38 +0x6e

Goroutine 8 (running) created at:
  main.deduplicate()
      /home/peter/gopath/src/racer.go:33 +0x190

Goroutine 7 (finished) created at:
  main.deduplicate()
      /home/peter/gopath/src/racer.go:33 +0x190
==================
==================
WARNING: DATA RACE
Write at 0x00c42007c150 by goroutine 9:
  runtime.mapassign_faststr()
      /home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
  main.write()
      /home/peter/gopath/src/racer.go:38 +0x6e

Previous write at 0x00c42007c150 by goroutine 7:
  runtime.mapassign_faststr()
      /home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
  main.write()
      /home/peter/gopath/src/racer.go:38 +0x6e

Goroutine 9 (running) created at:
  main.deduplicate()
      /home/peter/gopath/src/racer.go:33 +0x190

Goroutine 7 (finished) created at:
  main.deduplicate()
      /home/peter/gopath/src/racer.go:33 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c42007c150 by main goroutine:
  reflect.maplen()
      /home/peter/go/src/runtime/hashmap.go:1255 +0x0
  reflect.Value.MapKeys()
      /home/peter/go/src/reflect/value.go:1090 +0x421
  fmt.(*pp).printValue()
      /home/peter/go/src/fmt/print.go:739 +0x17fc
  fmt.(*pp).printArg()
      /home/peter/go/src/fmt/print.go:682 +0x19e
  fmt.(*pp).doPrintln()
      /home/peter/go/src/fmt/print.go:1136 +0x6e
  fmt.Fprintln()
      /home/peter/go/src/fmt/print.go:247 +0x65
  fmt.Println()
      /home/peter/go/src/fmt/print.go:257 +0x78
  main.main()
      /home/peter/gopath/src/racer.go:23 +0x1c3

Previous write at 0x00c42007c150 by goroutine 7:
  runtime.mapassign_faststr()
      /home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
  main.write()
      /home/peter/gopath/src/racer.go:38 +0x6e

Goroutine 7 (finished) created at:
  main.deduplicate()
      /home/peter/gopath/src/racer.go:33 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c42009a088 by main goroutine:
  reflect.typedmemmove()
      /home/peter/go/src/runtime/mbarrier.go:259 +0x0
  reflect.Value.MapIndex()
      /home/peter/go/src/reflect/value.go:1069 +0x232
  fmt.(*pp).printValue()
      /home/peter/go/src/fmt/print.go:750 +0x1867
  fmt.(*pp).printArg()
      /home/peter/go/src/fmt/print.go:682 +0x19e
  fmt.(*pp).doPrintln()
      /home/peter/go/src/fmt/print.go:1136 +0x6e
  fmt.Fprintln()
      /home/peter/go/src/fmt/print.go:247 +0x65
  fmt.Println()
      /home/peter/go/src/fmt/print.go:257 +0x78
  main.main()
      /home/peter/gopath/src/racer.go:23 +0x1c3

Previous write at 0x00c42009a088 by goroutine 7:
  main.write()
      /home/peter/gopath/src/racer.go:38 +0x84

Goroutine 7 (finished) created at:
  main.deduplicate()
      /home/peter/gopath/src/racer.go:33 +0x190
==================
map[foo:written bar:written baz:written]
Found 4 data race(s)
exit status 66

答案3

得分: 0

这个问题的本质是它可能会扩大。

英文:

The essence of this problem is that it may expand

huangapple
  • 本文由 发表于 2017年7月23日 02:49:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/45258055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定