首页 > 其他分享 >go中的map和锁

go中的map和锁

时间:2023-02-26 10:34:23浏览次数:42  
标签:map string func time go id

Go中的map和锁

声明和初始化

  • 只声明, var gMap map[string] string

使用var声明

  • 声明初始化
  • var hMap = map[string]string

使用make初始化

package main

import "fmt"

func main()  {
	var m = make(map[string]string)
	m["name"] = "Wyc"
	fmt.Println(m)
}

增删改查

package main

import (
	"fmt"
)

func main()  {
	var gMap map[string]string
	m2 := map[string]string{"k": "v"}
	fmt.Println(gMap)
	fmt.Println(m2["k"])
	// 增加
	m2["python"] = "Wyc"
	fmt.Println(m2)
	// 删除
	delete(m2, "python")
	fmt.Println(m2)
	// 改
	m2["k"] = "HAHA"
	fmt.Println(m2)
	// 查 单变量
	selectMapKey := m2["l"]
	// 双变量
	_, Bl  := m2["k"]
	fmt.Println(selectMapKey)
	if Bl {
		fmt.Println("存在")
	}else{
		fmt.Println("不存在")
	}
}
/*
结果
map[]
v
map[k:v python:Wyc]
map[k:v]
map[k:HAHA]

存在


*/

读取数据

  • 在读取的时候,有两种手段,第一种单变量 lang := mapData["key"], 如果当前key不存在就附一个value类型的0值
  • 第二种手段,双变量, value, bool := mapData["key"],可以根据bool来判断当前key是否存在,如果存在bool就为true,不存在则false

循环遍历map

package main

import "fmt"

func main()  {
	m2 :=  map[string]string{"name": "Wyc", "age": "23", "sex": "男"}

	fmt.Println(m2)
	for k, d := range m2{
		fmt.Printf("key: %v, value: %v\n", k, d)
	}


}
/*
结果
key: name, value: Wyc
key: age, value: 23
key: sex, value: 男
*/

key的类型:float64可以作为key吗

  • bool、int、string
  • 特征是支持 == 和 != 比较
  • float类型可以作为key的,写入map时会做math.Float64bits()的转换,认为2.4=2.4000xxxx1,看起来时同一个key

value的类型: 任意类型

  • map嵌套,每一层都需要make
package main

import "fmt"

func main()  {
	doubleM := make(map[string]map[string]string)
	v1 := make(map[string]string)
	v1["name"] = "Wyc"
	doubleM["v1"] = v1
	fmt.Println(doubleM)
}

go原生的map线程不安全

  • fatal error: concurrent map read and map write
package main

import "time"

func main()  {
	c := make(map[int]int)


	// goruntine 写
	go func() {
		for i:=0 ; i < 1000; i++{
			c[i] = i
		}
	}()

	// goruntine读

	go func() {
		for i:=0; i < 1000; i++{
			_ = c[i]
		}
	}()

	time.Sleep(30 * time.Minute)


}

go func 是什么意思?

运行匿名goruntine函数

map线程不安全的解决办法

解决办法一、加锁

  • go中的锁
  • 互斥锁
    • sync.mutex
      • 获取到互斥锁的任务,阻塞其他任务来获取
      • 意味这同一时间只能有一个任务去执行,才能持有互斥锁

package main

import (
	"log"
	"sync"
	"time"
)

// 互斥锁
var HcMutex sync.Mutex

func runMutex(id int) {
	log.Printf("[任务ID:%d]【尝试获取锁】", id)
	HcMutex.Lock()
	log.Printf("[任务ID:%d]【获取到了锁】", id)
	time.Sleep(6 * time.Second)
	HcMutex.Unlock()
	log.Printf("[任务ID:%d]【工作完成 释放锁】", id)
}

func sendText() {

	go runMutex(1)
	go runMutex(2)
	go runMutex(3)
	go runMutex(4)
}

func main() {

	sendText()
	time.Sleep(6 * time.Minute)

}

/*
2023/02/25 17:52:18 [任务ID:2]【尝试获取锁】
2023/02/25 17:52:18 [任务ID:1]【尝试获取锁】
2023/02/25 17:52:18 [任务ID:4]【尝试获取锁】
2023/02/25 17:52:18 [任务ID:3]【尝试获取锁】
2023/02/25 17:52:18 [任务ID:2]【获取到了锁】
2023/02/25 17:52:24 [任务ID:2]【工作完成 释放锁】
2023/02/25 17:52:24 [任务ID:1]【获取到了锁】
2023/02/25 17:52:30 [任务ID:1]【工作完成 释放锁】
2023/02/25 17:52:30 [任务ID:4]【获取到了锁】
2023/02/25 17:52:36 [任务ID:4]【工作完成 释放锁】
2023/02/25 17:52:36 [任务ID:3]【获取到了锁】
2023/02/25 17:52:42 [任务ID:3]【工作完成 释放锁】
*/

  • 读写锁
    • 同时多个读锁任务,说明使用读写任务的读锁,可以同时施加多把读锁
    • 同时多个写锁任务,说明如果并非使用读写锁的时候,退化成了互斥锁
    • 西安启动写锁任务,后并大5个读锁任务,当有写锁存在时,读锁是施加不了的,写锁释放完,读锁可以施加多个
package main

import (
	"log"
	"sync"
	"time"
)

var LockObj sync.RWMutex


func Readlock(id int)  {
	log.Printf("读任务id: %d, [进入写方法尝试获取读写锁]", id)
	LockObj.RLock()
	log.Printf("读任务id: %d, [获取到了读锁-开始干活休眠10s]", id)
	time.Sleep(10 * time.Second)
	LockObj.RUnlock()
	log.Printf("读任务id: %d, [读任务完成-释放]", id)
}


func WriteLock(id int){
	log.Printf("写任务id: %d, [进入写方法尝试获取读写锁]", id)
	LockObj.Lock()
	log.Printf("写任务id: %d, [获取到了写任务-开始干活休眠10s]", id)
	time.Sleep(10 * time.Second)
	LockObj.Unlock()
	log.Printf("写任务id: %d, [写任务完成-释放]", id)

}


func read()  {
	for i := 0; i < 10; i++ {
		go Readlock(i)
	}
}

func write()  {
	for i := 0; i < 10; i++ {
		go WriteLock(i)
	}
}



 // 先启动写锁
func writeFirst()  {
	go WriteLock(1)
	time.Sleep(1 * time.Second)
	go Readlock(1)
	go Readlock(2)
	go Readlock(3)
	go Readlock(4)
	go Readlock(5)
}


func readFirst()  {
	go Readlock(1)
	go Readlock(2)
	go Readlock(3)
	go Readlock(4)
	go Readlock(5)
	time.Sleep(1 * time.Second)
	go WriteLock(1)

}


func main()  {
	log.Println("进入程序")
	writeFirst()
	time.Sleep(1 * time.Hour)
	
}

解决办法二、使用sync.map

  • go 1.9 引入内置方法,并发线程安全的map
  • sync.Map 将key和value, 按照interface{}存储
  • 查询出来后要类型断言 x.(int) x.(string)
  • 遍历使用range 方法,需要传入一个匿名函数作为参数,匿名函数的

标签:map,string,func,time,go,id
From: https://www.cnblogs.com/wuyongcong/p/17156212.html

相关文章

  • django.template.exceptions.TemplateDoesNotExist: rest_framework/api.html
    django.template.exceptions.TemplateDoesNotExist:rest_framework/api.html报错,使用postman进行提交请求是能正常调用的,但是使用浏览器就会抛出这个错误这是因为没在set......
  • Map
      介绍ES6提供了Map数据结构。它类似于对象,也是键值对的集合。但是“键的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所......
  • VUEX mapActions 和 mapMutations
     不使用mapActions和mapMutations的代码要用的地方字体放大了<template><divid="app"><h1>当前总数为:{{nbr}}</h1><h2>放大十倍总数为:{{bigSum}}......
  • VUEX mapState 和 mapGetters的使用
       mapState:首先要在使用sore文件的文件引入:import{mapState}from'vuex';在js;红色的是用到的mapState可以自动生成计算属性   <script>import{mapState,m......
  • Go语言初尝
    概述对于语言设计之争,唯一需要牢记的一句话是:如果把C变成C++,那么C就消失了。Go是一个轻量级的简洁的支持并发的现代语言,可以用于探索性个人项目,这是我想学这......
  • Go编程实战:博客备份
    在“博客备份”一文中,编写了两个python脚本,然后使用一个命令行将博客备份流程串联起来。这里,我们将使用Go来实现。不太熟悉Go语言的读者,可以阅读之前写的两篇文章......
  • python-djanggo 实现读取excel 表格在网页中展示
    1.准备读取数据放到项目文件夹下   2.熟悉表结构    3.准备处理依赖库pipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simplepandasopenpyxl  ......
  • Golang微服务(二)
    Golang微服务(二)目录Golang微服务(二)注册中心选型consul环境consul常用API服务的增删查、健康检查gRPC的健康检查服务的负载均衡(相同服务多实例注册)配置中心nacos环境nacos......
  • Golang基于Mysql分布式锁实现集群主备
    背景集群中如果需要主备,可以基于Redis、zk的分布式锁等实现,本文将介绍如何利用Mysql分布式锁进行实现。原理数据库中包含数据字段(此处为Master的主机名)、版本号和上......
  • vue图片热区map-area定位(适应屏幕)
    vue代码<template><div>{{screenWidth}}{{screeHeight}}<divv-for="(item,index)inbook":key="index"><!--当从后台获取数据的时候可以进行......