嗨,这里是代码,我使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
}
所以这个工具的目的是作为一个缓存,类似的值只被加载一次,但被读取很多次。然而,当一个收集器的对象被传递给多个goroutine时,我面临着goroutine和ram使用的增加,每当多个goroutine试图使用收集器缓存时。有人能解释一下同步Map的使用是否正确吗?如果是的话,那么是什么原因导致了大量的goroutine/较高RAM使用率
2条答案
按热度按时间xggvc2p61#
当然,由于没有调用新创建的
ctxWithTimeout
上下文的cancel函数,您可能会遇到内存泄漏。为了解决这个问题,请将该行更改为:多亏了这个,你总是可以确保在上下文过期后清理所有分配的资源,这应该可以解决泄漏的问题。
关于
sync.Map
的用法我觉得不错。让我知道这是否解决了您的问题,或者如果有其他问题需要解决,谢谢!
qxsslcnc2#
您在读取器端显示代码,但不显示执行请求(并调用
.Store(key, value)
)的代码。使用您显示的代码:
empty
值保存在map中(当执行c.keyValMap.LoadOrStore(key, empty)
时),[更新后]
在资源消耗方面,收集器的代码本身似乎是可以的:我在这段代码中并没有看到死锁或者goroutine的乘法。
您可能应该查看代码中的其他地方。
同样,如果这个结构只增长不收缩,它肯定会消耗更多的内存,一定要审计你的程序,评估有多少不同的键可以在你的缓存中共存,以及缓存的值可以占用多少内存。