c# IDistributedCache 的 Get 和 GetAsync 有什么区别

来源:这里教程网 时间:2026-02-21 17:43:14 作者:

IDistributedCache.Get
IDistributedCache.GetAsync
的根本区别是同步阻塞 vs 异步非阻塞

前者会**直接阻塞当前线程**直到缓存读取完成(比如 Redis 网络往返结束),后者返回

Task<byte></byte>
,让线程可以去做别的事,等 I/O 完成后再继续——这对 ASP.NET Core 这类高并发服务至关重要。

在 Web 应用中,用

.Get()
而不是
.GetAsync()
会导致线程池饥饿、吞吐量下降,尤其在缓存后端(如 Redis)延迟升高时更明显。这不是“能不能用”的问题,而是“该不该用”的架构选择。

为什么
Get
还存在?它适合什么场景

IDistributedCache.Get
是同步包装,底层通常调用
GetAsync().GetAwaiter().GetResult()
(或类似实现)。它只在极少数明确需要同步上下文的场合才合理:

单元测试中快速验证逻辑,不希望引入
async Task
测试方法
Legacy 同步代码迁移过渡期,且确认调用栈不会进入 Web 请求生命周期 后台定时任务里用到了非 async 主循环(但更推荐统一改用
GetAsync
+
await

注意:

.Get()
在 ASP.NET Core 请求处理中调用,可能引发死锁或
AspNetCoreSynchronizationContext
相关异常,尤其是配合某些旧版中间件时。

GetAsync
的参数和典型用法细节

GetAsync
签名是:
public Task<byte[]?> GetAsync(string key, CancellationToken token = default);

关键点:

key
必须是非 null 字符串;传 null 会直接抛
ArgumentNullException
CancellationToken
可用于主动取消等待(例如请求超时、客户端断开),不传则用
default
(即无取消信号)
返回值是
byte[]?
:缓存未命中时为
null
,不是空数组;需判空,不能直接
Encoding.UTF8.GetString(result)
它只负责读原始字节,不自动反序列化;若你存的是 JSON 字符串,读出来后得自己
JsonSerializer.Deserialize<t>(bytes)</t>

常见误写示例(错在没 await):

var data = _cache.GetAsync("user:123"); // ❌ 返回 Task,没 await,data 是 Task 对象本身
string json = Encoding.UTF8.GetString(data.Result); // ❌ 阻塞式取 Result,等同于 Get()

正确写法:

var bytes = await _cache.GetAsync("user:123");
if (bytes is not null)
{
    string json = Encoding.UTF8.GetString(bytes);
    // 处理 json...
}

性能与兼容性影响:别被名字骗了

名字带 “Async” 不代表一定快,但代表「不抢线程」。实际耗时取决于网络 RTT、Redis 负载、序列化开销——这些对

Get
GetAsync
是一样的。

真正差异在于调度行为:

Get
:占用一个线程池线程全程等待,期间无法响应其他请求
GetAsync
:发起 I/O 后立即释放线程,操作系统完成网络读取后唤醒回调,线程复用率更高

在 .NET 6+ 默认配置下,

IDistributedCache
的 Redis 实现(
StackExchange.Redis
)完全基于异步 I/O,所以
Get
内部也是靠
GetAsync
+
Wait()
模拟出来的——这多一次线程挂起/唤醒开销,纯属负优化。

除非你在写控制台工具或单元测试这种对吞吐无要求的场景,否则永远优先选

GetAsync
,并确保调用链上所有方法都标记
async
、用
await
。漏掉一个
await
,就等于白加。

相关推荐

热文推荐