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语言的编译和工具链