英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论