go语言协程安全map

前言:

在go语言中 map 是很重要的数据结构。Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。问题来了,这么安逸的 数据结构,它不是协程安全的 !当多个 协程同时对一个map 进行 读写时,会抛出致命错误。总结一下 想要 做到 协程安全 map 一共有以下三种方法。

1.map + 锁

这是最常见的一种操作,当要对 map操作的时候就加锁,其他的 协程就等待。下面是代码示例:

package util

import "sync"

type SafeMap struct {
    Data map[string]interface{}
    Lock sync.RWMutex
}

func (this *SafeMap) Get(k string) interface{} {
    this.Lock.RLock()
    defer this.Lock.RUnlock()
    if v, exit := this.Data[k]; exit {
        return v
    }
    return nil
}

func (this *SafeMap) Set(k string, v interface{}) {
    this.Lock.Lock()
    defer this.Lock.Unlock()
    if this.Data == nil {
        this.Data = make(map[string]interface{})
    }
    this.Data[k] = v
}

  

2. sync.map

这个是go 最近版本新推出来的 协程安全 map == 可能是官方也觉得 蛮有必要的吧 。下面的代码 主要写一下使用方法。具体原理我就不介绍了。这里要注意一下 sync.map 不需要 初始化

var test sync.Map

//设置元素
func set (k,v interface{}){
    test.Store(k,v)
}

//获得元素
func get (k interface{}) interface{}{
    tem ,exit := test.Load(k)
    if exit {
        return tem
    }
    return nil
}

//传入一个 函数 ,sync.map  会内部迭代 ,运行这个函数
func ranggfunc (funcs func(key, value interface{}) bool) {
    test.Range(funcs)
}

//删除元素
func del(key interface{}){
    test.Delete(key)
}

3.单协程操作 map ,用 channle 通信

这个思路有点 骚,就是一直由一个协程 操作map ,其他协程 通过 channle 告诉这个协程应该 怎么操作。其实这样子 性能不是很好,因为 channle 底层 也是锁 ,而且 map 存数据 是要 计算hash的 ,之前是 多个协程自己算自己的hash ,现在变成了一个协程计算了。但是这个思路还是可以,不仅仅是 在 map上可以这么操作。socket 通信啊, 全局 唯一对象的调用啊,都可以用此思路。下面给大家看一下我是实现的代码:

package main

import (
    "fmt"
    //"time"
)

var (
    ADD  interface{} = 1
    DEL  interface{} = 2
    GET  interface{} = 3
)

type safeMap struct {
    Msq     chan *[3] interface{}       //[‘type‘,‘id‘,‘value‘,channle]
    data    map[interface{}]interface{}
    chanl   chan interface{}
}

func NewSafeMap() *safeMap {
    tem := &safeMap{}
    tem.init()
    return tem
}

func (this *safeMap) init() {
    this.Msq   = make(chan *[3]interface{},10)
    this.data  = make(map[interface{}]interface{})
    this.chanl = make(chan interface{},0)
    go this.run()
}

func (this *safeMap) run() {
    for {
        select {
        case msg := <- this.Msq :
            switch msg[0] {
            case ADD :
                this.dataAdd(msg[1],msg[2])
            case DEL :
                this.dataDel(msg[1])
            case GET :
                this.dataGet(msg[1])
            }
        }
    }
}

func (this *safeMap) msqChan (typ,id,val interface{}) *[3]interface{}{
    return &[...]interface{}{typ,id,val}
}

//保存 或者更新元素
func (this *safeMap) dataAdd (id , value interface{}) {
    this.data[id] = value
}

//删除元素
func (this *safeMap) dataDel (id interface{}) {
    delete(this.data,id)
}

//获得元素
func (this *safeMap) dataGet (id interface{}) {
    if val ,exit := this.data[id] ;exit {
        this.chanl <- val
        return
    }
    this.chanl <- nil
}

//----------------------------------------------------对外接口--------------------------------
func (this *safeMap) Add (id ,value interface{}) {
    this.Msq <- this.msqChan(ADD,id,value)
}

func (this *safeMap) Del (id interface{}) {
    this.Msq <- this.msqChan(DEL,id ,nil)
}

func (this *safeMap) Get (id interface{}) interface{} {
    this.Msq <- this.msqChan(GET,id,nil)
    res := <- this.chanl
    return res
}

//获得 长度
func (this *safeMap) GetLength() uint32{
    return uint32(len(this.data))
}

func main() {
    sa := NewSafeMap()

//  sa.Add(1,1)
    sa.Add(2,3)
    fmt.Println(2,sa.Get(2))
    sa.Del(2)
    fmt.Println(2,sa.Get(2))
}

  

原文地址:https://www.cnblogs.com/wsw-seu/p/11665855.html

时间: 2024-11-07 05:00:25

go语言协程安全map的相关文章

状态机/迭代器/LINQ/协程

状态机 有限状态机(Finite State Machine 或 Finite State Automata)是软件领域中一种重要的工具. 状态机允许一个对象在其内部状态改变时改变它的行为.对象内部状态决定行为方式,对象状态改变行为方式改变,这里强调内部状态. Command 模式是将命令请求封装成一个为对象,将不同的请求对象参数化以达到同样的调用执行不同的命令: State 模式是将对象的状态封装成一个对象,是在不同的状态下同样的调用执行不同的操作. 迭代器是一个典型的状态机例子,后续会讲解.

ucontext-人人都可以实现的简单协程库

1.干货写在前面 协程是一种用户态的轻量级线程.本篇主要研究协程的C/C++的实现. 首先我们可以看看有哪些语言已经具备协程语义: 比较重量级的有C#.erlang.golang* 轻量级有python.lua.javascript.ruby 还有函数式的scala.scheme等. c/c++不直接支持协程语义,但有不少开源的协程库,如: Protothreads:一个"蝇量级" C 语言协程库 libco:来自腾讯的开源协程库libco介绍,官网 coroutine:云风的一个C语

coroutine协程

如果你接触过lua这种小巧的脚本语言,你就会经常接触到一个叫做协程的神奇概念.大多数脚本语言都有对协程不同程度的支持.但是大多编译语言,如C/C++,根本就不知道这样的东西存在.当然也很多人研究如何在编译语言实现协程的实现,轮子一个又一个的被发明.酷壳 这篇文章<一个“蝇量级” C 语言协程库>说的很详细,但对于文中介绍的协程库protothread,很难看的懂.风云大哥在搜索无满意结果后也重新发明轮子,实现自己版本的一个协程库<C 的 coroutine 库>, 风云版本的cor

golang 单协程和多协程的性能测试

测试数据:单协程操作1亿数据,以及多协程(10条协程)操作1亿数据(每条协程操作1kw数据) 废话少说,贴代码: 单协程测试运算: package main import ( "fmt" "time" ) func testNum(num int) { for i := 1; i <= 10000000; i++{ num = num + i num = num - i num = num * i num = num / i } } func main() {

FreeRTOS基础以及UIP之协程--C语言剑走偏锋

在FreeRTOS中和UIP中,都使用到了一种C语言实现的多任务计数,专业的定义叫做协程(coroutine),顾名思义,这是一种协作的例程, 跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程技巧. 意思就是说协程不需要每次调用的时候都为任务准备一次空间,我们知道像ucos这种操作系统,它内置的多任务是需要在中断过程中切换堆栈的,开销较大,而协程的功能就是在尽量降低开销的情况下,实现能够保存函数上下文快速切换的办法,用操作系统的概念来说,一千个

day05 协程函数,递归函数,匿名函数lambda,内置函数map reduce filter max min zip sorted,匿名函数lambda和内置函数结合使用,面向过程编程与函数编程,模块与包的使用,re模块内置函数

基础篇 本章大纲: 协程函数 递归函数 匿名函数lambda 内置函数map reduce filter  max min zip sorted 匿名函数lambda和内置函数结合使用 面向过程编程与函数编程 模块与包的使用 re模块内置函数 一,协程函数 注意:函数先定义,后使用.这是函数第一原则.函数主要分为定义,调用 1.1,什么是协程函数 协程函数特点:yield变为表达式,可以通过g.send(value)传值,用send传值时协程函数需要初始化,也可以说是生成器函数的一种 1.2,协

c语言实现的协程

这几天突然对协程感兴趣,于是自己实现了一个,代码放在github上:https://github.com/adinosaur/Coro 协程是一种用户空间的非抢占式线程,主要用来解决等待大量的IO操作的问题. 协程vs线程 对比使用多线程来解决IO阻塞任务,使用协程的好处是不用加锁,访问共享的数据不用进行同步操作.这里需要说明的一点是,使用协程之所以不需要加锁不是因为所有的协程只在一个线程中运行,而是因为协程的非抢占式的特点.也就是说,使用协程的话,在没主动交出CPU之前都是不会被突然切换到其它

轻量级协程库C语言实现

仿制云风的协程库的接口设计,我花了一个下午加晚上的时间重构了之前写的协程库,提供的接口现在和云风大大的协程接口一模一样,都是仿制lua的非对称协程.我们依旧没有用ucontext.h组件(用ucontext.h组件实现协程的文章铺天盖地,可以自行寻找,用longjmp实现就少很多,用内联汇编实现的就更少了),我们的协程库可以运行在兼容X86平台的操作系统上,各种unix-like操作系统,windows操作系统都可以,不过得用gcc或者clang或者与之兼容的mingw编译工具编译出32位的程序

转:一个C语言实现的类似协程库(StateThreads)

http://blog.csdn.net/win_lin/article/details/8242653 译文在后面. State Threads for Internet Applications Introduction State Threads is an application library which provides a foundation for writing fast and highly scalable Internet Applications on UNIX-li