首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Go中对单个计算代价高昂的资源的多个请求

在Go中对单个计算代价高昂的资源的多个请求
EN

Stack Overflow用户
提问于 2019-12-12 23:07:02
回答 3查看 199关注 0票数 0

寻找一种更具Go风格的解决方案来解决以下问题:

比方说,服务器有多个并行传入的请求,请求具有密钥key的资源。由于计算此资源是昂贵的/耗时的,我们希望确保只计算一次。有无限多个可能的键。

一个简单的实现:

代码语言:javascript
运行
复制
if hasCachedValue(key) {
   return cachedValue(key)
}
if somebodyElseWorkingOn(key) {
   waitUntilReady(key)
} else {
   buildCacheValue(key) // time consuming
}
return cachedValue(key)

到目前为止,我们已经使用共享map[string]chan bool解决了这个问题,其中第一个请求为key插入更改,随后的请求在值准备就绪时等待该更改的关闭。为了保护地图,我们使用了sync.Mutex,但我们有一种感觉,那就是有一个更好、更有活力的解决方案。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-12-13 02:03:02

使用singleflight包。为组声明一个包级变量:

代码语言:javascript
运行
复制
var g singleflight.Group

使用以下代码获取该值:

代码语言:javascript
运行
复制
v, err, _ := g.Do(key, func() (interface{}, error) {
    if !hasCachedValue(key) {
        buildCacheValue(key)
    }
    return cachedValue(key), nil
})
if err != nil {
    // handle error
}
x := v.(valueType) // assert to type returned by cachedValue
// do something with x
票数 2
EN

Stack Overflow用户

发布于 2019-12-13 00:40:48

下面是一段简单的代码,它可以完成您想要的操作。我测试了它,它工作正常,没有问题。Go竞速状态检查器没有检测到任何问题。

代码语言:javascript
运行
复制
type Cache struct {
    mtx sync.RWMutex
    m map[KeyType]*CacheValue
}

type CacheValue struct {
    val *ValueType
    mtx sync.Mutex
}

func NewCache() *Cache {
    return &Cache{m: make(map[KeyType]*CacheValue)}
}

func (c *Cache) Get(key KeyType) *ValueType {
    c.mtx.RLock()
    v := c.m[key]
    c.mtx.RUnlock()
    if v != nil {
        v.mtx.Lock()
        x := v.val
        v.mtx.Unlock()
        if x != nil {
            return x
        }
    }

    if v == nil {
        c.mtx.Lock()
        v = c.m[key]
        if v == nil {
            v = &CacheValue{}
            c.m[key] = v
        }
        c.mtx.Unlock()
    }

    v.mtx.Lock()
    if v.val == nil {
        v.val = buildValue(key)
    }
    v.mtx.Unlock()
    return v.val
}
票数 0
EN

Stack Overflow用户

发布于 2019-12-13 16:28:44

受到经常用于描述通道的乒乓示例的启发,我们坐下来尝试了一种仅限通道的方法。一个ball保存有关正在生成的密钥的状态,并且ball在请求之间传递一个共享通道:

代码语言:javascript
运行
复制
import "time"

var table = make(chan map[string]chan bool)

func keeper() {
    for {
        ball := <- table
        table <- ball
    }
}

func getResource(key string) {
    // Take ball from table
    ball := <- table

    if wait, ok := ball[key]; ok{
        println("Somebody else working on " + key + ", waiting")
        table <- ball
        <- wait
    } else {
        println("I will build " + key)
        ball[key] = make(chan bool)

        // Throw away ball
        table <- ball

        // Building value
        time.Sleep(time.Millisecond * 10)
        println("I built value for " + key + "!")

        // Clean up ball
        ball = <- table
        close(ball[key])
        delete(ball, key)
        table <- ball
    }

    println("Now value for " + key + " has been built")
}

func main(){
    go keeper()

    ball := make(map[string]chan bool)
    table <- ball

    key := "key"
    go getResource(key)
    go getResource(key)
    go getResource(key)

    time.Sleep(time.Second)
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59307534

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档