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

高频请求场景下函数调用限流与缓存优化方案问询

高并发场景下的IsRaining()缓存优化方案梳理

先聊聊你的场景:你有一个每秒处理约10万次请求的服务,每次请求都得通过IsRaining()判断天气来调整行为,核心逻辑是:

if(IsRaining()) return "You probably shouldn't go anywhere today."; //... otherwise proceed

咱们逐个分析现有方案的问题,再打磨出符合你需求的通用实现。

版本1:性能瓶颈的根源

最开始的实现直接调用外部服务,这是明显的性能短板,高并发下会把大量时间耗在外部调用上:

public bool IsRaining() => ExternalService.IsRaining();

版本2:缓存优化,但遇到时间查询的CPU瓶颈

你针对业务需求(下雨状态变更可延迟感知,但停雨要立即知晓)做了缓存策略:如果上次检测是下雨,就立刻重新校验;没下雨的话,1秒内复用缓存。但当请求量涨到每秒数十万时,DateTime.UTCNow的调用居然占了50%的CPU,这就成了新的性能瓶颈:

bool isRainingCache;
DateTime lastChecked;
public bool IsRaining() {
 DateTime now = DateTime.UTCNow;
 // 如果上次检测为下雨则重新校验;若未下雨,仅当距上次检测超过1秒时才重新校验
 if (isRainingCache || (now - lastChecked) > TimeSpan.FromSeconds(1)) {
 isRainingCache = ExternalService.IsRaining();
 lastChecked = now;
 }
 return isRainingCache;
}

版本3:异步过期的尝试,但隐患不少

为了减少时间查询的开销,你尝试了异步清空缓存的方案,但这个方案没经过测试,还存在不少问题:“即发即弃”的Task可能会滥用系统资源;服务销毁时会遗留未完成的任务;而且如果对TPL不熟悉,换成Timer或Thread又容易引发shutdown时的资源清理问题。另外原代码里return false明显是笔误,应该返回缓存值:

bool? isRainingCache = null;
public bool IsRaining() {
 // 仅当缓存为空或上次检测为下雨时,才重新校验
 if (isRainingCache == null || isRainingCache == true) {
 isRainingCache = ExternalService.IsRaining();
 // 若未下雨,1秒后清空缓存以触发重新校验
 if(!isRainingCache) Task.Run(() => Task.Delay(1000).ContinueWith(() => {
 isRainingCache = null;
 }));
 }
 return isRainingCache.Value; // 修正原代码的笔误
}

目标:通用的Throttled<T>抽象类

你希望把这个逻辑封装成通用类,像这样简洁使用:

// 最多每1000毫秒调用一次getter,否则返回缓存值
public Throttled<bool> IsRaining = new Throttled<bool>(() => Service.IsRaining, 1000);

更优的通用Throttled<T>实现

结合你的业务需求和高并发场景,我设计了这个线程安全、资源可控的通用类:

public class Throttled<T> : IDisposable
{
    private readonly Func<T> _getter;
    private readonly TimeSpan _cacheDuration;
    private T _cachedValue;
    private DateTime _nextRefreshTime;
    private readonly object _lockObj = new object();
    private CancellationTokenSource _cts;

    public Throttled(Func<T> getter, int cacheDurationMilliseconds)
    {
        _getter = getter ?? throw new ArgumentNullException(nameof(getter));
        _cacheDuration = TimeSpan.FromMilliseconds(cacheDurationMilliseconds);
        _cts = new CancellationTokenSource();
        // 初始化时先获取一次值
        _cachedValue = _getter();
        UpdateNextRefreshTime();
    }

    public T GetValue()
    {
        // 针对bool类型的特殊业务规则:如果当前是下雨状态,立即刷新
        if (typeof(T) == typeof(bool) && Equals(_cachedValue, true))
        {
            lock (_lockObj)
            {
                if (Equals(_cachedValue, true)) // double-check避免锁竞争
                {
                    _cachedValue = _getter();
                    UpdateNextRefreshTime();
                }
            }
            return _cachedValue;
        }

        // 非下雨状态,检查是否到刷新时间
        var now = DateTime.UtcNow;
        if (now >= _nextRefreshTime)
        {
            lock (_lockObj)
            {
                if (now >= _nextRefreshTime) // double-check
                {
                    _cachedValue = _getter();
                    UpdateNextRefreshTime();
                }
            }
        }
        return _cachedValue;
    }

    private void UpdateNextRefreshTime()
    {
        // 未下雨时设置缓存时长,下雨时下次立即刷新
        if (typeof(T) == typeof(bool) && Equals(_cachedValue, false))
        {
            _nextRefreshTime = DateTime.UtcNow + _cacheDuration;
        }
        else
        {
            _nextRefreshTime = DateTime.UtcNow;
        }
    }

    public void Dispose()
    {
        _cts.Cancel();
        _cts.Dispose();
    }
}

这个实现的优势

  • 线程安全:用double-check lock模式处理高并发场景下的缓存读写,避免竞争问题
  • 减少时间查询开销:只在需要判断非下雨状态的缓存是否过期时才调用DateTime.UtcNow,下雨状态直接跳过时间判断
  • 贴合业务需求:自动区分两种天气状态的缓存策略,不用在业务代码里重复写逻辑
  • 资源可控:实现IDisposable接口,服务销毁时可以妥善释放资源,避免遗留任务
  • 通用灵活:不仅支持bool类型的天气判断,也能适配其他需要节流缓存的场景

使用时就像你期望的那样简单:

public Throttled<bool> IsRaining = new Throttled<bool>(() => ExternalService.IsRaining(), 1000);

// 在业务代码里调用
if(IsRaining.GetValue()) {
    return "You probably shouldn't go anywhere today.";
}
// 继续处理其他逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:08:11