暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Go-Sync(共享)下

花一个无所 2019-09-10
209

题图:pixabay

临时对象池sync.Pool

临时对象池,顾名思义。临时存储对象的池子。

在什么场景会用到呢?缓存。嘚,就是有更好,没有我就自己搞一个。

sync.Pool、sync.Cond、sync/atomic、sync.WaitGroup、sync.Once都属于结构体类型哈。

sync.Pool有两个方法:参数都是interface{}类型

Get() 如果有,返回这个值。并把它从池子里delete掉。如果没有,调用New字段(注意是一个字段,不是一个方法。它的类型才是:func() interface{})创建一个新的(这个值是池子初始化的时候设定的)。但是这个值只会返回给调用方,不会存储在池子里。Put()

池子中的值在GC开始前,都会被全面清除。

那么这个池子会在啥时候被销毁呢?

在sync包初始化的时候,会在运行时系统里注册一个方法,这个方法的功能就是就是清除所有已创建的临时对象池中的值。go运行时系统在每次即将GC时会执行这个方法。在包里还有一个私有全局变量,汇总了当前程序中使用的所有临时对象池 []*sync.Pool 类型的切片。一个临时对象池第一次使用的时候就被注册进这个全局变量了。清除方法的步骤:

遍历切片,将每一个对象池的对象都置为nil将切片重置为空切片

怎么保证一个临时对象池子里总有充足的临时对象?

用完了还回去。

并发字典sync.Map

原生的map在并发的时候会产生竞态问题,是非并发安全的。除非加上锁 mutex。但是这是要写代码的。但是go出了一个这种高级数据结构Map,帮你实现了并发安全。它内部也是用了锁机制,不过它是尽可能少的用锁(用锁肯定会降低程序性能)。

Map 类型所有的方法涉及的键和值的类型都是interface{},但是键的实际类型不能是函数类型、字典类型和切片类型。这里比较难搞的一点就是传参键值都是interface。存取的时候都需要用断言去整一下子。除非固定某种类型。

上面说Map尽可能少的用锁。这是很关键的,那它是怎么尽可能少的?

Map 在内部用了很多原子操作来存取键值,并用了两个原生map作为存储介质。一个map用做read字段类型,一个用作dirty字段类型。键类型都是interface{}。存储只会存储指针。

read作为只读字典,不对键操作,只操作值。所以read字段替换的时候不需要锁。在操作值的时候,还封装了一层。把值转为unsafe.Pointer类型。方便利用原子操作。


文章转载自花一个无所,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论