一切皆有可能:Golang中的“ThreadLocal”库
本文介绍的是新写的
routine
库,它封装并提供了一些易用、高性能的
goroutine
上下文访问接口,可以帮助你更优雅地访问协程上下文信息,但你也可能就此打开了潘多拉魔盒。
介绍
Golang
语言从设计之初,就一直在不遗余力地向开发者屏蔽协程上下文的概念,包括协程
goid
的获取、进程内部协程状态、协程上下文存储等。
如果你使用过其他语言如
C++/Java
等,那么你一定很熟悉
ThreadLocal
,而在开始使用
Golang
之后,你一定会为缺少类似
ThreadLocal
的便捷功能而深感困惑与苦恼。当然你可以选择使用
Context
,让它携带着全部上下文信息,在所有函数的第一个输入参数中出现,然后在你的系统中到处穿梭。
而
routine
的核心目标就是开辟另一条路:将
goroutine local storage
引入
Golang
世界,同时也将协程信息暴露出来,以满足某些人可能有的需求。
使用演示
此章节简要介绍如何安装与使用
routine
库。
安装
go get github.com/go-eden/routine
使用
goid
以下代码简单演示了
routine.Goid()
与
routine.AllGoids()
的使用:
package main
import (
"fmt"
"github.com/go-eden/routine"
"time"
func main() {
go func() {
time.Sleep(time.Second)
goid := routine.Goid()
goids := routine.AllGoids()
fmt.Printf("curr goid: %d\n", goid)
fmt.Printf("all goids: %v\n", goids)
此例中
main
函数启动了一个新的协程,因此
Goid()
返回了主协程
1
,
AllGoids()
返回了主协程及协程
18
:
curr goid: 1
all goids: [1 18]
使用
LocalStorage
以下代码简单演示了
LocalStorage
的创建、设置、获取、跨协程传播等:
package main
import (
"fmt"
"github.com/go-eden/routine"
"time"
var nameVar = routine.NewLocalStorage()
func main() {
nameVar.Set("hello world")
fmt.Println("name: ", nameVar.Get())
// 其他协程不能读取前面Set的"hello world"
go func() {
fmt.Println("name1: ", nameVar.Get())
// 但是可以通过Go函数启动新协程,并将当前main协程的全部协程上下文变量赋值过去
routine.Go(func() {
fmt.Println("name2: ", nameVar.Get())
// 或者,你也可以手动copy当前协程上下文至新协程,Go()函数的内部实现也是如此
ic := routine.BackupContext()
go func() {
routine.InheritContext(ic)
fmt.Println("name3: ", nameVar.Get())
time.Sleep(time.Second)