You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Go协程实现内存缓存并进行定时更新?

嘿,这个用内存缓存+Go协程定时更新的思路太靠谱了,刚好我之前做过类似的天气API代理场景,给你梳理下把getWeather移到main并启动协程之后,需要重点关注的几个关键点和代码示例:

核心实现要点

1. 线程安全的缓存容器

因为协程在后台更新缓存,同时你的API请求在读取缓存,必须用线程安全的存储结构,不然会出现数据竞争问题。最常用的是带读写互斥锁的结构体,比sync.Map更直观:

import (
    "sync"
    "time"
    "net/http"
    "encoding/json"
    "log"
)

// 假设这是从第三方API返回的天气数据结构
type WeatherData struct {
    City     string  `json:"city"`
    Temp     float64 `json:"temp"`
    Humidity int     `json:"humidity"`
}

type WeatherCache struct {
    mu   sync.RWMutex // 读写锁,读多写少场景更高效
    data WeatherData
}

2. 定时更新的协程实现

用time.Ticker来实现每秒更新比time.Sleep循环更可靠,它能保证固定间隔触发,不会因为单次API调用耗时导致间隔偏移:

func getWeather() (WeatherData, error) {
    // 这里是调用第三方天气API的逻辑,返回数据或错误
    // 示例模拟返回数据
    return WeatherData{
        City:     "Beijing",
        Temp:     22.5,
        Humidity: 60,
    }, nil
}

func main() {
    var cache WeatherCache

    // 先初始化缓存,避免第一个请求拿到空数据
    initialData, err := getWeather()
    if err == nil {
        cache.mu.Lock()
        cache.data = initialData
        cache.mu.Unlock()
    }

    // 启动定时更新协程
    ticker := time.NewTicker(1 * time.Second)
    defer ticker.Stop() // 程序退出时停止ticker

    go func() {
        for range ticker.C {
            newData, err := getWeather()
            if err != nil {
                log.Printf("Failed to fetch weather data: %v", err)
                continue // 出错时不覆盖旧缓存,保持可用数据
            }

            cache.mu.Lock()
            cache.data = newData
            cache.mu.Unlock()
            log.Println("Weather cache updated successfully")
        }
    }()

    // 启动你的API服务,这里用标准库net/http示例
    http.HandleFunc("/weather", func(w http.ResponseWriter, r *http.Request) {
        cache.mu.RLock()
        defer cache.mu.RUnlock() // 读操作用读锁,支持并发读

        w.Header().Set("Content-Type", "application/json")
        if err := json.NewEncoder(w).Encode(cache.data); err != nil {
            http.Error(w, "Failed to encode response", http.StatusInternalServerError)
        }
    })

    log.Println("Server starting on :8080...")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

3. 关键细节优化

  • 缓存初始化:启动服务时先主动拉取一次数据,避免第一个请求返回空值;
  • 错误容错:第三方API报错时不覆盖现有缓存,保证你的API始终能返回有效数据;
  • 读写锁效率:用sync.RWMutex而不是普通sync.Mutex,因为读请求远多于写请求,读写锁支持多个并发读,性能更好;
  • 资源清理:用defer ticker.Stop()确保程序退出时释放ticker资源,避免内存泄漏。

如果后续需要扩展,比如支持多城市缓存、持久化缓存(重启不丢失),可以在这个基础上调整缓存结构,比如把WeatherData改成map[string]WeatherData存储多城市数据,或者加上Redis作为二级缓存。

内容的提问来源于stack exchange,提问作者Ahmed Ashraf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:01:51