SYNC.MAP

161 阅读2分钟

SYNC.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
// 并发读写,采用读写锁,更为常见
// 但是go syn.map中采用了一种效率更高的并发安全,与MAP不同,不是语言原生态提供的,而是sync包下的特殊结构
/*sync.Map有以下特性:
1. 无需初始化,直接声明
2. 不能使用map方式进行,使用sync.Map进行调参,Store表示存储,Load表示获取,Delete表示删除
3.使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。
**/
package 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")

   scene.Range(func(k, v interface{}) bool {
      fmt.Println("iterate", k, v)
      return true
   })
}

/*
第 24 行,Range() 方法可以遍历 sync.Map,遍历需要提供一个匿名函数,
参数为 k、v,类型为 interface{},每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。
sync.Map 没有提供获取 map 数量的方法,替代方法是在获取 sync.Map 时遍历自行计算数量,
sync.Map 为了保证并发安全有一些性能损失,因此在非并发情况下,使用 map 相比使用 sync.Map 会有更好的性能。
*/

//length := 0
//
//myMap.Range(func(_, _ interface{}) bool {
//length++
//
//return true
//})
// 上面的代码是用来计算syn.Map的长度的,但是 哈哈哈哈哈哈,很明显看出如果两个一起访问,那么就会变少了
//而且sync.Map的变化会不确定的导致range的变化

//https://medium.com/@deckarep/the-new-kid-in-town-gos-sync-map-de24a6bf7c2c
//很离谱的事情发生了
// 1. sync.Map不是基于map
// 2. sync.Map并且,它的range不安全,不能反应长度
// 3. sync.Map而且他的性能不一定比map好

上面是之前看的笔记,奇奇怪怪的,哈哈哈哈哈,下面认真的写一下吧

上面主要是对比了sync.map和map+sync.rwmutex的区别和联系。 先介绍以下sync.map,是用在map的安全并发,使用的是三个函数load(),store(),和delete(),以及还有一个range。

不过range真的 哈哈哈哈,是用来遍历的,但是不是很好用了,sync.map可不是一个适合遍历的东西

还探讨了,在map+rwmutex以及基本实现互斥功能的情况下,为什么需要sync.map

原因是:在多核高并发服务器上的性能sync.map会更好(虽然一般情况下,比如我的电脑map+rmwmutex会更好)

sreramk.medium.com/go-inside-s…