美文网首页
Goroutine的上下文存储(续)

Goroutine的上下文存储(续)

作者: 元家昕 | 来源:发表于2018-10-31 19:13 被阅读0次

要做Goroutine级别的存储,首先是要获取到Goroutine的标识,之前提到过获取routine id的两个库,效率也比较低下,用在性能要求比较苛刻的场景下并不适合。

最近看到有个通过go汇编获取goid的方法,https://chai2010.cn/advanced-go-programming-book/ch3-asm/ch3-08-goroutine-id.html。原理其实很简单,golang的内部其实是存储了routineid的,放在了runtime2.go文件的g struct中,只不过这个struct是私有变量,不可以通过外部访问。通过go汇编,我们可以绕过go语言层级带来的障碍,直接访问到对象所在的内存。

获取到goid以后,我们就可以通过map来存储上下文了。

新的问题是,golang的map并不是线程安全,并发的读写会产生问题。实现过程中需要考虑多线程的安全问题。原文提供的方案比较简单,就是在读写过程中对map加互斥锁。进一步的优化方案是使用RWMutex,读map的时候加RLock,写操作加互斥锁,这个也是golang官方推荐的方案,https://blog.golang.org/go-maps-in-action

golang的sync包下面,也有一套map的同步方案,sync/map.go,那么这个方法又有什么特点,我们该怎么选择呢?看了源码以后,发现这一套方案主要是通过空间换时间的方法来减少锁的使用,内部通过两个map存储数据,老的数据存放在read map,新数据存放dirty map,如果数据特征是一次写入,多次读出,那么多数的读请求都会落入read map,不需要加锁,从而提升并发性能。

那么,实际过程中,这三种方案的性能表现到底如何呢?我对不同的读写比例和不同的并发程度做了benchmark,详情见下图。直接上结论,在读写比例100:1以下时RWMutex方案有绝对优势,更高的读写比例下,sync.Map的方案具有更高的性能;RWMutex和sync.Map的性能在大部分情况下都比单锁的方案高,并发程度越高,优势越明显。

10次读操作 100次读操作 1000次读操作

回到我们的场景,上下文存储经常用来处理http server请求相关的数据,减少层层传参。这种场景下,读写比例不会非常高,所以一般来说RWMutex方案是最优的选择。

实现代码和bechmark代码见github,https://github.com/JasonYuan/gls.git

另,在看sync.Map的过程中,顺便看了下sync.atomic,顾名思义,这是保证各种数据操作原子性的的库。看到一个有意思的事情,在amd64下,大部分的内置类型实际上都可以保证写入的原子性,但是interface类型是不能保证的,原因是interface的内部存储是个struct,同时保存了类型和地址。这时候可以通过atomic.Value来实现,实现过程无锁,可以放心服用。

相关文章

  • Goroutine的上下文存储(续)

    要做Goroutine级别的存储,首先是要获取到Goroutine的标识,之前提到过获取routine id的两个...

  • Goroutine的上下文存储

    后端开发中,问题分析通常是请求级别的,如果能通过一个唯一的请求号对日志进行过滤,能对分析问题带来不少的便捷。我们的...

  • golang -context

    1. 简介 go 1.7 开始引入context(上下文),准确地说是goroutine 的上下文。主要在goro...

  • 【golang】HTTP服务器的request互相传递数据

    context:上下文,不仅可以设置超时控制Goroutine,还可在上下文中进行传值

  • golang context上下文信息

    当需要在多个 goroutine 中传递上下文信息时,可以使用 Context 实现。Context 除了用来传递...

  • context.go

    context主要用于跨多个Goroutine设置截止时间、同步信号、传递上下文请求值,没了解过Context的先...

  • Go语言Context(上下文)---goroutine上下文

    参考:https://www.flysnow.org/2017/05/12/go-in-action-go-con...

  • Go 语言学习笔记-Goroutine和channel

    Goroutine 什么是 Goroutine Goroutine 是 Go 并行设计的核心。Goroutine ...

  • 变量对象 - 2023-02-09

    变量对象 变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。因为不同执行上下文下的变量...

  • 策略模式例子

    思路:在自定义上下文中存储所有的处理类,在其他类中引入上下文,从上下文中根据订单类型获取对应的处理类进行订单处理。...

网友评论

      本文标题:Goroutine的上下文存储(续)

      本文链接:https://www.haomeiwen.com/subject/tnjltqtx.html