4 回答

TA貢獻(xiàn)1155條經(jīng)驗(yàn) 獲得超0個(gè)贊
如果并發(fā)進(jìn)程向全局變量寫入相同的值會(huì)怎樣?
數(shù)據(jù)競(jìng)爭(zhēng)的結(jié)果是不確定的。
運(yùn)行 Go 數(shù)據(jù)競(jìng)爭(zhēng)檢測(cè)器。
參考:
良性數(shù)據(jù)競(jìng)賽:可能出現(xiàn)什么問題?
Go:數(shù)據(jù)競(jìng)爭(zhēng)檢測(cè)器
在 Go 1.6 中,運(yùn)行時(shí)添加了輕量級(jí)的、最大努力的映射并發(fā)濫用檢測(cè)。此版本改進(jìn)了該檢測(cè)器,支持檢測(cè)同時(shí)寫入和遍歷映射的程序。
與往常一樣,如果一個(gè) goroutine 正在寫入 map,則沒有其他 goroutine 應(yīng)該同時(shí)讀取(包括迭代)或?qū)懭?map。如果運(yùn)行時(shí)檢測(cè)到這種情況,它會(huì)打印診斷并使程序崩潰。找出更多有關(guān)問題的最佳方法是在競(jìng)爭(zhēng)檢測(cè)器下運(yùn)行程序,這將更可靠地識(shí)別競(jìng)爭(zhēng)并提供更多詳細(xì)信息。
例如,
package main
import "time"
var linksToVisit = map[string]bool{}
func main() {
someLink := "someLink"
go func() {
for {
linksToVisit[someLink] = true
}
}()
go func() {
for {
linksToVisit[someLink] = true
}
}()
time.Sleep(100 * time.Millisecond)
}
輸出:
$ go run racer.go
fatal error: concurrent map writes
$
$ go run -race racer.go
==================
WARNING: DATA RACE
Write at 0x00c000078060 by goroutine 6:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/map_faststr.go:190 +0x0
main.main.func2()
/home/peter/gopath/src/racer.go:16 +0x6a
Previous write at 0x00c000078060 by goroutine 5:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/map_faststr.go:190 +0x0
main.main.func1()
/home/peter/gopath/src/racer.go:11 +0x6a
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:14 +0x88
Goroutine 5 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:9 +0x5b
==================
fatal error: concurrent map writes
$

TA貢獻(xiàn)1893條經(jīng)驗(yàn) 獲得超10個(gè)贊
如果您使用多個(gè) go 例程同時(shí)更改相同的值,則最好使用鎖。由于當(dāng)另一個(gè)函數(shù)正在更改相同值時(shí),無論何時(shí)都使用互斥鎖和鎖來保護(hù)值不被訪問,就像在訪問同一個(gè)表時(shí)寫入數(shù)據(jù)庫(kù)表一樣。
對(duì)于您關(guān)于使用具有不同鍵的地圖的問題,在 Go 中并不可取,因?yàn)椋?/p>
map 的典型使用不需要從多個(gè) goroutine 進(jìn)行安全訪問,在需要的情況下,map 可能是某個(gè)更大的數(shù)據(jù)結(jié)構(gòu)或已經(jīng)同步的計(jì)算的一部分。因此,要求所有映射操作都獲取一個(gè)互斥量會(huì)減慢大多數(shù)程序的速度并增加少數(shù)程序的安全性。
只有在發(fā)生更新時(shí),地圖訪問才是不安全的。只要所有 goroutines 都只是讀取——查找地圖中的元素,包括使用 for range 循環(huán)遍歷它——而不是通過分配給元素或進(jìn)行刪除來更改地圖,它們就可以安全地同時(shí)訪問地圖而無需同步。
因此,不建議更新地圖。有關(guān)詳細(xì)信息,請(qǐng)查看關(guān)于為什么映射操作未定義為原子的常見問題解答。
還注意到,如果你真的想去 for 應(yīng)該有一種方法來同步它們。
映射對(duì)于并發(fā)使用是不安全的:它沒有定義當(dāng)你同時(shí)讀取和寫入它們時(shí)會(huì)發(fā)生什么。如果您需要從并發(fā)執(zhí)行的 goroutine 讀取和寫入映射,則訪問必須通過某種同步機(jī)制進(jìn)行調(diào)解。保護(hù)地圖的一種常見方法是使用 sync.RWMutex。

TA貢獻(xiàn)1993條經(jīng)驗(yàn) 獲得超6個(gè)贊
并發(fā)映射寫入不正常,因此您很可能會(huì)遇到致命錯(cuò)誤。所以我認(rèn)為應(yīng)該使用鎖

TA貢獻(xiàn)1801條經(jīng)驗(yàn) 獲得超16個(gè)贊
從 Go 1.6 開始,同時(shí)寫入 map 將導(dǎo)致panic
. 使用 async.Map
同步訪問。
查看映射值分配實(shí)現(xiàn): https://github.com/golang/go/blob/fe8a0d12b14108cbe2408b417afcaab722b0727c/src/runtime/hashmap.go#L519
- 4 回答
- 0 關(guān)注
- 165 瀏覽
添加回答
舉報(bào)