Go語言中的map在并發情況下,只讀是線程安全的,同時讀寫是線程不安全的。
```
package main
func main() {
// 創建一個int到int的映射
m := make(map[int]int)
// 開啟一段并發代碼
go func() {
// 不停地對map進行寫入
for {
m[1] = 1
}
}()
// 開啟一段并發代碼
go func() {
// 不停地對map進行讀取
for {
_ = m[1]
}
}()
// 無限循環,讓并發程序在后臺執行
for {}
}
```
運行代碼會報錯,輸出如下:
~~~
fatal error: concurrent map read and map write
~~~
錯誤信息顯示,并發的map讀和map寫,即說使用了兩個并發不斷地對map進行讀和寫而發生了競態問題,map內部會對這種并發操作進行檢查并提前發現。
需要并發讀寫時,一般的做法是加鎖,但這樣性能并不高。Go語言在1.9版本中提供了一種效率較高的并發安全的sync.Map,sync.Map和map不同,不是以語言原生形態提供,而是在sync包下的特殊結構。
sync.Map有以下特性:
* 無須初始化,直接聲明即可;
* sync.Map不能使用map方式進行取值和設置等操作,而是使用sync.Map的方法進行調用。Store表示存儲,Load表示獲取,Delete表示刪除;
* 使用Range配合一個回調函數進行遍歷操作,通過回調函數內部遍歷出來的值,Range參數中回調參數的返回值在需要繼續迭代遍歷時,返回true,終止迭代遍歷時,返回false
```
pacage main
import (
"fmt"
"sync"
)
func main() {
var scene sync.Map
// 將鍵值對保存到sync.Map
scene.Store("greece", 97)
scene.Store("london". 100)
scene.Store("egypt", 200)
// 從sync.Map中根據鍵值對取值
fmt.Println(scene.Load("london"))
// 根據鍵刪除對應的鍵值對
scene.Delete("london")
// 遍歷所有sync.Map
scene.Range(func(k, v interface{}) bool {
fmt.Println("iterate:", k, v)
return true
})
}
```
- 1.Go語言前景
- 2.Go語言環境搭建
- 3.Go語言的基本語法
- 3.1變量
- 3.1.1變量聲明
- 3.1.2變量初始化
- 3.1.3多個變量同時賦值
- 3.1.4匿名變量
- 3.1.5變量的作用域
- 3.1.6整型
- 3.1.7浮點類型
- 3.1.8復數
- 3.1.9bool類型
- 3.1.10字符串
- 3.1.11字符類型
- 3.1.12類型轉換
- 3.2常量
- 3.1.1const關鍵字
- 3.2.2模擬枚舉
- 4.Go語言的流程控制
- 4.2循環結構
- 4.3鍵值循環
- 4.4switch語句
- 4.5goto語句
- 4.6break語句
- 4.7continue語句
- 5.Go語言的函數
- 5.1函數聲明
- 5.2函數變量
- 5.3函數類型實現接口
- 5.4閉包
- 5.5可變參數
- 5.6defer(延遲執行語句)
- 5.7處理運行時錯誤
- 5.8宕機(panic)
- 5.9宕機恢復(recover)
- 5.10Test功能測試函數
- 6.Go語言的內置容器
- 6.1數組
- 6.2切片
- 6.3map
- 6.4sync.Map
- 6.5list
- 6.6range
- 7.Go語言的結構體
- 8.Go語言的接口
- 9.Go語言的常用內置包
- 10.Go語言的并發
- 11.Go語言的文件I/O操作
- 12.Go語言的網絡編程
- 13.Go語言的反射
- 14.Go語言的數據庫編程
- 15.Go語言密碼學算法
- 16.Go語言的gin框架
- 17.Go語言的網絡爬蟲
- 18.Go語言的編譯和工具鏈