惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
V
Visual Studio Blog
博客园_首页
Last Week in AI
Last Week in AI
Apple Machine Learning Research
Apple Machine Learning Research
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
SegmentFault 最新的问题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Martin Fowler
Martin Fowler
Recent Announcements
Recent Announcements
J
Java Code Geeks
月光博客
月光博客
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
F
Fortinet All Blogs
P
Privacy & Cybersecurity Law Blog
C
CERT Recently Published Vulnerability Notes
C
CXSECURITY Database RSS Feed - CXSecurity.com
B
Blog RSS Feed
S
Schneier on Security
酷 壳 – CoolShell
酷 壳 – CoolShell
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
W
WeLiveSecurity
A
Arctic Wolf
U
Unit 42
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
有赞技术团队
有赞技术团队
Recorded Future
Recorded Future
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
大猫的无限游戏
大猫的无限游戏
Microsoft Security Blog
Microsoft Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
量子位
B
Blog
T
The Exploit Database - CXSecurity.com
C
Cisco Blogs
博客园 - 三生石上(FineUI控件)
H
Help Net Security
博客园 - 叶小钗
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LINUX DO - 热门话题
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
小众软件
小众软件
雷峰网
雷峰网
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security

博客园 - 邓磊Lei

为什么 Go 一个 HTTP 服务可以同时处理数万连接 gin怎么处理一次http请求的 我的经验:git提交信息分别用什么icon C# 也能像 Python 一样写脚本 | .NET 10 构建基于文件的应用 .NET 10 使用 Microsoft.AspNetCore.OpenApi 实现 API 版本管理 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 Microsoft Agent Framework + Kimi API 实战:控制台应用跑通单次与多轮 Agent 对话 开发实战:asp.net core + ef core 实现动态可扩展的分页方案 聊聊 ASP.NET Core 中间件和过滤器的区别 Python 入门:从“其他语言”到 Pythonic 思维的完整迁移手册 .NET 进阶之路:异步、并发与内存管理的系统性认知 Redis:延迟双删的适用边界与落地细节 Serilog:从结构化日志认知到 .NET 工程落地 EF Core 原生 SQL 实战:FromSql、SqlQuery 与对象映射边界 EF Core 拦截器实战:SaveChangesInterceptor、CommandInterceptor 与审计落地 ASP.NET Core 外部依赖调用治理实战:HttpClientFactory、Polly 与幂等边界 EF Core 慢查询排查实战:TagWith、OpenTelemetry、执行计划,30 分钟定位性能瓶颈 EF Core 并发冲突实战:乐观锁、RowVersion 与 DbUpdateConcurrencyException 怎么处理 EF Core 写入链路深拆:从 ChangeTracker 到 SQL Batch 的性能诊断与优化 ASP.NET Core 认证鉴权实战:JWT、Policy 与权限边界怎么落地 C# 异步编程深水区:Task、ValueTask、线程池饥饿与背压设计 EF Core 查询性能黑洞:Include、投影与跟踪策略的边界 从 IApplicationBuilder 到 RequestDelegate:ASP.NET Core 请求管线的性能与可观测性实战 如何在 rider 中配置 SonarQube
.NET .Result 避坑指南:不同框架下的死锁与线程池饥饿
邓磊Lei · 2026-03-17 · via 博客园 - 邓磊Lei

这篇只讲一个知识点:在 .NET 代码里用 .Result(或 GetAwaiter().GetResult())同步阻塞异步任务,为什么在不同框架下会触发不同类型的事故。

问题背景

同样一行代码,在两个系统里出现了完全不同的故障:

  • 老系统(ASP.NET MVC 5)请求直接卡死,不返回
  • 新系统(ASP.NET Core)不是直接死锁,而是高峰期吞吐突然掉到很低,请求排队超时

两边都有这段写法:

public string GetData()
{
    return GetDataAsync().Result;
}

private async Task<string> GetDataAsync()
{
    await Task.Delay(50);
    return "ok";
}

原理:同一个坑,两种后果

场景 1:ASP.NET Classic / WinForms / WPF(有 SynchronizationContext)

这类框架默认要求 continuation 回到原上下文(UI 线程或请求上下文)。

.Result 先把当前线程阻塞住,Task 完成后 continuation 又想回到这条线程,结果互相等待:

  1. 当前线程在 .Result 处阻塞
  2. continuation 需要回到当前线程继续执行
  3. 当前线程被阻塞,continuation 进不来
  4. 死锁

所以你会看到"请求一直转圈"或"界面完全卡死"。

场景 2:ASP.NET Core(默认无 SynchronizationContext)

在默认配置下,ASP.NET Core 没有传统的请求级 SynchronizationContext,所以通常不会触发上面的经典互锁。

它会把线程池工作线程同步阻塞住。并发一上来,越来越多线程被卡在 .Result,线程池来不及补充,新请求拿不到线程,就出现线程饥饿:

  • CPU 不一定高
  • 数据库不一定慢
  • 但接口耗时和超时数暴涨

这就是"看起来不像死锁,但系统几乎不可用"的典型表现。

最小对照示例

public sealed class DemoService
{
    // ❌ 错误:同步包装异步
    public int GetNumber()
    {
        return GetNumberAsync().Result;
    }

    // ✅ 正确:异步到底
    public async Task<int> GetNumberAsync()
    {
        await Task.Delay(10);
        return 42;
    }
}

如何避坑(只保留最关键三条)

  1. 不要在任何业务调用链上使用 .Result / .Wait() / GetAwaiter().GetResult()
  2. API、Service、Repository 全链路改成 async,不要做"同步方法包异步"。
  3. 如果历史包袱必须保留同步签名,就让边界层同步,内部仍然异步,避免层层阻塞传染。

一句结论

.Result 在老框架里更容易直接死锁,在 ASP.NET Core 里更容易演化成线程池饥饿;表现不同,本质相同,都是"阻塞等待异步"导致的。