20分钟
3.8.5 goid的应用: 局部存储
有了goid之后,构造Goroutine局部存储就非常容易了。我们可以定义一个gls包提供goid的特性:
package gls
var gls struct {
m map[int64]map[interface{}]interface{}
sync.Mutex
}
func init() {
gls.m = make(map[int64]map[interface{}]interface{})
}
gls包变量简单包装了map,同时通过sync.Mutex
互斥量支持并发访问。
然后定义一个getMap内部函数,用于获取每个Goroutine字节的map:
func getMap() map[interface{}]interface{} {
gls.Lock()
defer gls.Unlock()
goid := GetGoid()
if m, _ := gls.m[goid]; m != nil {
return m
}
m := make(map[interface{}]interface{})
gls.m[goid] = m
return m
}
获取到Goroutine私有的map之后,就是正常的增、删、改操作接口了:
func Get(key interface{}) interface{} {
return getMap()[key]
}
func Put(key interface{}, v interface{}) {
getMap()[key] = v
}
func Delete(key interface{}) {
delete(getMap(), key)
}
最后我们再提供一个Clean函数,用于释放Goroutine对应的map资源:
func Clean() {
gls.Lock()
defer gls.Unlock()
delete(gls.m, GetGoid())
}
这样一个极简的Goroutine局部存储gls对象就完成了。
下面是使用局部存储简单的例子:
import (
gls "path/to/gls"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
defer gls.Clean()
defer func() {
fmt.Printf("%d: number = %d\n", idx, gls.Get("number"))
}()
gls.Put("number", idx+100)
}(i)
}
wg.Wait()
}
通过Goroutine局部存储,不同层次函数之间可以共享存储资源。同时为了避免资源泄漏,需要在Goroutine的根函数中,通过defer语句调用gls.Clean()函数释放资源。
学员评价