Go语言 同步Map可能导致资源不足

3qpi33ja  于 2022-12-07  发布在  Go
关注(0)|答案(2)|浏览(125)

这里是我把util称为公共资源收集器的代码

import (
    "context"
    "errors"
    "sync"
    "time"
)

type Collector struct {
    keyValMap *sync.Map
}

func (c *Collector) LoadOrWait(key any) (retValue any, availability int, err error) {
    value, status := c.getStatusAndValue(key)

    switch status {
    case 0:
        return nil, 0, nil
    case 1:
        return value, 1, nil
    case 2:
        ctxWithTimeout, _ := context.WithTimeout(context.Background(), 5 * time.Second)
        for {
            select {
            case <-ctxWithTimeout.Done():
                return nil, 0, errRequestTimeout
            default:
                value, resourceStatus := c.getStatusAndValue(key)
                if resourceStatus == 1 {
                    return value, 1, nil
                }
                time.Sleep(50 * time.Millisecond)
            }
        }
    }

    return nil, 0, errRequestTimeout
}

// Store ...
func (c *Collector) Store(key any, value any) {
    c.keyValMap.Store(key, value)
}

func (c *Collector) getStatusAndValue(key any) (retValue any, availability int) {
    var empty any
    result, loaded := c.keyValMap.LoadOrStore(key, empty)

    if loaded && result != empty {
        return result, 1
    }

    if loaded && result == empty {
        return empty, 2
    }

    return nil, 0
}

所以这个工具的作用是作为一个缓存,类似的值只被加载一次,但是被读取很多次。但是当一个CommonResourceCollector的对象被传递给多个goroutine时,我面临着一些goroutine的饥饿和可能的泄漏。有人能解释一下sync Map的使用是否正确吗?如果是的话,那么是什么原因导致了goroutine的饥饿?

nx7onnlm

nx7onnlm1#

当然,由于没有调用新创建的ctxWithTimeout上下文的cancel函数,您可能会面临内存泄漏。为了解决这个问题,请将该行更改为:

ctxWithTimeout, cancelFunc := context.WithTimeout(context.Background(), requestTimeout)
defer cancelFunc()

因此,一旦上下文过期,您总是可以确保清理所有分配的资源。这应该可以解决泄漏问题。
关于sync.Map的用法对我来说似乎不错。
让我知道这是否解决了您的问题,或者如果有其他问题需要解决,谢谢!

zi8p0yeb

zi8p0yeb2#

您显示的是读取器端的代码,而不是执行请求(并调用.Store(key, value))的代码。
使用您显示的代码:

  • 第一个试图访问一个给定键的goroutine会把你的empty值存储在map中(当执行c.keyValMap.LoadOrStore(key, empty)时),
  • 所以所有的goroutine在查询同一个键时都会进入“超时查询”循环--即使实际运行请求并将结果存储该高速缓存中的动作没有被执行。

这是你的问题吗?

相关问题