当前位置: 首页 > article >正文

别被 `run_in_threadpool` 骗了,它只是个“背锅侠”!

如果你在写 FastAPI 或者基于 Starlette 的应用那你一定遇到过这种进退两难的时刻你手里有一段祖传的同步阻塞代码比如老旧的requests.get或者某个不支持异步的数据库驱动但你的路由是被async def定义的“纯血异步”函数。这时候如果你直接把同步代码塞进去整个异步事件循环就会像被施了定身法一样瞬间卡死吞吐量直接清零。于是你开始疯狂查阅文档终于找到了那个金光闪闪的 API——run_in_threadpool。你兴奋地把它包在同步代码外面一跑果然不卡了你长舒一口气以为自己完美解决了并发问题。但真相是你并没有解决阻塞你只是花钱雇了个“背锅侠”。而且如果不了解它的底细这个背锅侠迟早会把你的服务器搞垮。今天我们就来扒一扒run_in_threadpool的底裤看看这玩意儿到底是个啥。第一幕微波炉与傻站着的厨师要彻底懂这其中的奥秘我们先来复习一下“同步Sync”和“异步Async”到底有什么区别。把我们的程序想象成一家高档餐厅而服务器的 CPU 和主事件循环就是这家餐厅里唯一的超级服务员。真正的异步比如httpx.AsyncClient微波炉模式服务员接到客人的点单把菜放进微波炉按下 10 分钟倒计时。然后立刻转身去招呼其他几百个客人。微波炉“叮”一声响了I/O 完成通知服务员再去端菜。结果单核一个服务员轻松应对千万并发没有任何人闲着。同步阻塞比如requests.get傻站着模式服务员接到点单把菜下锅然后死死盯着这口锅看 10 分钟。这 10 分钟内门外排队的几百个客人全都在骂街因为服务员被卡住了。结果吞吐量暴跌服务器“假死”。第二幕run_in_threadpool登场背锅侠就位为了防止超级服务员被这口锅卡死FastAPI 祭出了run_in_threadpool这块创可贴。当你使用它时到底发生了什么这段代码奇迹般地变成微波炉了吗绝对没有这道菜依然需要人站在锅边死等run_in_threadpool只是做了一个障眼法超级服务员一看这道菜要死等为了不让自己被骂他立刻跑到后厨花钱雇了一个临时工开辟了一个子线程。服务员对临时工说“老哥你帮我站在这口锅前死等 10 分钟好了叫我哈”随后超级服务员一身轻松立刻转身回大堂继续接客了。这就是run_in_threadpool的真相它并没有把同步变异步它只是把“阻塞卡顿”的这口锅甩给了后台新建的子线程。对于主程序超级服务员来说他不卡了但对于这段代码本身它依然是阻塞的。第三幕定时炸弹——“临时工”是有限的既然能雇临时工那我把所有同步代码都用run_in_threadpool包起来不就天下太平了如果你敢这么干你的服务器离崩溃就不远了。因为这种“假异步”有一个致命的弱点线程池的数量是有上限的。在 FastAPI底层依赖 anyio中默认的线程池大小通常是40 个。这意味着你的后厨最多只能容纳 40 个临时工。假设你同时来了 40 个很慢的请求超级服务员雇了 40 个临时工大家都在后厨死等。当第41 个请求来的时候灾难发生了。服务员回头一看“卧槽雇不到人了” 此时这第 41 个请求只能在大堂苦苦排队。从用户的角度来看你的服务器依然卡死了不管你怎么刷新都在转圈。而如果是真正的异步微波炉模式哪怕同时来 10000 个请求服务员只需要把 10000 盘菜放进 10000 个微波炉按一下按钮就行了单线程就能搞定根本不需要雇佣临时工。第四幕终极禁忌——千万别让临时工干“体力活”如果你觉得线程池耗尽已经够惨了那run_in_threadpool还有一个能让 Python 直接吐血的禁忌用它来执行 CPU 密集型任务纯粹的数值计算、图像处理等。这又回到了 Python 的祖传大坑——GIL全局解释器锁。在同一间厨房进程里有且只有一把“炒菜用的铁铲GIL”。如果是 I/O 阻塞比如等网络请求临时工是在“傻等”不需要拿铁铲会释放 GIL超级服务员可以继续拿铁铲干活两不相干。如果是重度计算临时工必须死死握住这把铁铲疯狂干活。这时候超级服务员如果想去大堂端盘子执行 Python 异步逻辑就会发现铁铲被临时工抢走了两人开始疯狂争夺同一把铁铲。最终的结果是你的代码不仅依然只能在一个 CPU 核心上跑而且因为主线程和子线程疯狂抢夺 GIL整体性能反而比不加还要慢总结法则拿捏 FastAPI 并发的正确姿势写到这里是时候总结一波避坑口诀了原汤化原食在异步框架里永远首选原生支持 async 的第三方库如httpx,asyncpg,aiofiles。这是真理是王道。创可贴用法如果迫不得已必须调用同步 I/O 库并且确定并发量不高可以用run_in_threadpool或者直接写普通的def路由FastAPI 底层也是放进线程池。它能救急但别当饭吃。计算任务靠边站如果你有消耗大量 CPU 的任务视频处理、大矩阵运算请绝对远离run_in_threadpool正确做法是开辟全新的厨房使用ProcessPoolExecutor或外部任务队列如 Celery Redis让它们在其他多核 CPU 上奔跑。别再被run_in_threadpool骗了它只是个尽职尽责的背锅侠。善待它别把它累死。

相关文章:

别被 `run_in_threadpool` 骗了,它只是个“背锅侠”!

如果你在写 FastAPI 或者基于 Starlette 的应用,那你一定遇到过这种进退两难的时刻: 你手里有一段祖传的同步阻塞代码(比如老旧的 requests.get 或者某个不支持异步的数据库驱动),但你的路由是被 async def 定义的“纯…...

笔试训练48天:删除公共字符

REAL507 删除公共字符 https://www.nowcoder.com/practice/f0db4c36573d459cae44ac90b90c6212?tpId182&tqId34789&ru/exam/oj 简单 通过率:32.96% 时间限制:1秒 空间限制:32M 知识点Java工程师字符串2017模拟C工程师 描述 输…...

英飞凌TC377芯片选型指南:从300MHz主频到292引脚封装,工程师如何快速匹配项目需求?

英飞凌TC377芯片选型实战:300MHz三核架构与汽车级外设的工程权衡 当汽车ECU设计遇上工业控制器开发,芯片选型往往成为项目成败的第一道分水岭。英飞凌AURIX™系列中的TC377以其300MHz主频三核架构和丰富的外设接口,在新能源车电控系统与高端工…...

Elasticsearch实战篇:索引库、文档与JavaRestClient操作指南

Elasticsearch 实战篇:索引库、文档与 JavaRestClient 操作指南整理自黑马程序员《SpringCloud微服务开发与实战》Elasticsearch01 课程 对应章节:索引库操作、文档操作、JavaRestClient 客户端一、索引库操作 (Index Operations) 索引库类似于 MySQL 中…...

跨平台开发实战:ClearerVoice-Studio在Qt应用中的集成

跨平台开发实战:ClearerVoice-Studio在Qt应用中的集成 1. 引言 在语音应用开发中,我们经常遇到这样的场景:用户录制的语音充满背景噪音,多人对话混在一起难以分辨,或者需要从复杂音频中提取特定说话人的声音。传统解…...

cubeIDE创建不了,是版本的问题,然后你要下载包,不能没有STM32的固件包

...

生成式AI搜索优化失效真相:从BERT重排到MUM升级,3层语义理解断层如何精准修复?

第一章:生成式AI应用搜索优化策略 2026奇点智能技术大会(https://ml-summit.org) 在生成式AI应用快速落地的背景下,传统搜索引擎对AI原生内容(如LLM生成文本、合成图像元数据、多模态响应日志)的索引与排序能力已显著滞后。优化…...

从仿真到实战:如何用MATLAB生成的白光干涉信号验证你的测量算法?

从仿真到实战:MATLAB白光干涉信号生成与算法验证全流程指南 在光学测量领域,白光干涉技术因其独特的优势成为表面形貌检测、薄膜厚度测量等精密工程应用的核心手段。然而,实际系统开发中最令人头疼的环节往往不是硬件搭建,而是测量…...

Spring AI 大特性,你知道几个?

前面几篇聊了 Spring AI 的搭建、特色功能和一些偏聊天场景的案例。今天换个口味,聊两个我最近在生产环境里折腾出来的真实案例——多模态数据处理和批量流水线。 说实在的,现在的AI教程十个有九个都在讲“怎么写一个聊天机器人”,但企业里真…...

Matlab实战:sensorArrayAnalyzer工具箱在传感器阵列设计与分析中的应用

1. 从零开始认识sensorArrayAnalyzer工具箱 第一次听说Matlab的sensorArrayAnalyzer工具箱时,我正在做一个智能音箱的麦克风阵列优化项目。当时团队纠结于阵列参数的选择,直到我发现这个神器——它把晦涩的阵列理论变成了可视化的交互操作。简单来说&…...

【好靶场】你知道unionId吗

基础知识微信开放平台是一个公司的总账号,AppID 是旗下每个应用的唯一标识,UnionID 则是用户在该公司所有应用里的统一身份,用于跨应用识别同一用户。这样微信用户在同一家公司下面的应用(公众号、小程序等)下&#xf…...

C语言这么牛,它自身又是用什么语言写的?真相很硬核

你有没有想过一个问题:世界上第一个C语言编译器,它是用什么语言写的?要解开这个谜团,我们得回到计算机的起点 CPU真正能读懂的,只有由0和1组成的机器语言。这是所有故事的基石。 那么,第一步是怎么走的呢&a…...

Phi-4-mini-reasoning 3.8B 智能文档处理:Typora风格Markdown内容自动生成

Phi-4-mini-reasoning 3.8B 智能文档处理:Typora风格Markdown内容自动生成 1. 场景痛点:Markdown写作的效率瓶颈 对于技术写作者、博客作者和文档工程师来说,Markdown已经成为事实上的标准写作格式。而Typora以其简洁优雅的所见即所得体验&…...

AI训练硬件指南:GPU算力梯队与任务匹配框架

AI训练硬件指南:GPU算力梯队与任务匹配框架算力评估维度CUDA核心数/Tensor核心数:并行计算基础能力显存容量与带宽:决定模型规模上限FP32/FP16/TF32计算性能:不同精度需求场景NVLink与PCIe通道:多卡扩展效率消费级GPU梯…...

企业微信异地打卡教程

最近捣鼓了一段时间发现了一款非常好用的企业微信可以在家打卡,自己可以测试噢 下载链接...

LightOnOCR-2-1B镜像免配置:集成Prometheus监控指标与Grafana可视化看板

LightOnOCR-2-1B镜像免配置:集成Prometheus监控指标与Grafana可视化看板 1. 开篇:为什么需要监控OCR服务? 当你部署了一个强大的OCR服务后,最关心的是什么?是识别准确率?是响应速度?还是服务稳…...

mac codex intel版本

20260417最新版...

LFM2.5-1.2B-Thinking-GGUF从零开始:无Python环境依赖的纯二进制GGUF部署方案

LFM2.5-1.2B-Thinking-GGUF从零开始:无Python环境依赖的纯二进制GGUF部署方案 1. 平台简介与核心优势 LFM2.5-1.2B-Thinking-GGUF是Liquid AI推出的轻量级文本生成模型,专为低资源环境优化设计。该镜像采用创新的纯二进制部署方案,完全摆脱…...

Flutter 入门第八课:网络请求与数据解析(对接后端实战)

这节课是 Flutter 实现前后端交互的核心,也是从「本地模拟数据」到「真实业务开发」的关键一步。我们会系统学习 Flutter 最主流的网络请求库Dio,掌握GET/POST 基础请求、请求 / 响应拦截器(统一处理请求头、错误、加载状态)、JSO…...

GEMINI编代码时输不出iloc[0]

这是我的对话记录,有没有大佬能帮帮我#你生成一行包括iloc[0],的python代码以下是包含 iloc, 的 Python 代码示例。在 pandas (Python Data Analysis Library) 中,这种语法通常用于提取数据并隐式构建单元素元组 (Tuple):Pythonfirst_record_…...

从理论到实测:全国电赛D题电路特性测试仪之输出阻抗、增益与上限频率实战解析

1. 输出阻抗测量:从理论到实战的关键细节 输出阻抗是电子电路设计中一个看似简单却暗藏玄机的参数。在实际比赛中,我们团队最初对输出阻抗的理解停留在课本定义上,直到动手测量才发现理论到实践的鸿沟。输出阻抗本质上反映了电路带负载能力的…...

STM32调试实战:Keil MDK + J-Link下局部变量消失的5种排查姿势

STM32调试实战:Keil MDK J-Link下局部变量消失的5种排查姿势 调试嵌入式系统时,局部变量突然"消失"是开发者常遇到的棘手问题。当你在Keil MDK环境中使用J-Link调试STM32,发现Watch窗口中的局部变量显示为"not in scope"…...

供应商评估模型:从课程设计、讲师背景、案例库到售后支持的全方位对比

选择培训或认证类供应商,本质上是在为企业的能力短板寻找最适配的“外挂大脑”。一个好的评估模型,应当把主观感受转化为可量化的指标。以下从课程设计、讲师背景、案例库、售后支持四个维度,提供一套加权评分框架。 一、评估模型核心逻辑 建议先确定各维度权重(总分100分…...

GEO 1.0 到 2.0:为什么 90% 的品牌优化是表面功夫

当用户问 “2026 年值得买的家用按摩仪”“适合新手的旗舰手机”“熬夜党必备的膳食营养品” 时,你的品牌,会出现在 AI 的回答里吗?会被放在首推位吗?这两年,生成式 AI 彻底改写了用户的信息获取与消费决策链路。从豆包…...

OFDM自适应调制的“智能”从哪来?深入聊聊信道状态信息(CSI)的获取与反馈那些坑

OFDM自适应调制背后的工程智慧:信道状态信息实战指南 在无线通信系统的设计与优化中,OFDM自适应调制技术如同一位隐形的调音师,实时调整着每个子载波的"音调"(调制方式)以适应瞬息万变的信道环境。但这位调音…...

Qt Widget控件属性详解

1. QWidget 可以在Qt Creator 右侧看到 QWidget 的各种属性2 QWidget常用属性 2.1 enabled 描述了一个控件是否”可用“状态,相对于”禁用“ 禁用:该控件不能接收任何用户的输入事件,并且外观上是灰色的如果一个 widget 被禁用,则…...

LeetCode442 数组中重复的数据|原地哈希空间优化算法C++深度题解

大家好,今日完成中等难度数组算法刷题,攻克面试高频空间限制难题。 本题核心考点:严格限制O(n)时间复杂度、只能常数额外空间,不能新开哈希表,力扣经典数组思维题。题目题意长度为n的数组,数字范围全部在 […...

Worlds End Club for Mac 软件详解与操作指南

本文来源:爱上MAC | 软件下载地址:Worlds End Club for Mac Worlds End Club 是一款在Mac平台上运行的叙事驱动型横向卷轴动作冒险游戏。它巧妙融合了视觉小说式的剧情叙述与平台跳跃、解谜及轻度战斗元素。本指南将详细介绍其软件界面、完整操作流程…...

算法训练营第五天| 203. 移除链表元素

题目建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。题目链接:https://leetcode.cn/problems/remove-linked-list-elements/视频讲解:https://www.bilibili.com/video/BV18B4y1s7R9解题思路:1.…...

JavaScript 中高效定位二维数组间差异元素的行列索引

...