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

asyncio + pytest 大坑:asyncio.create_task() 在测试中“卡死不动”

行,我给你压缩到一半长度,保留结论 + 关键机制 + 实操建议,直接能发博客那种。

 


 

 

⚠️ asyncio + pytest 大坑:

asyncio.create_task()

 在测试中“卡死不动”

 

 

结论先行
带 asyncio.create_task() 的后台异步代码,不要用 pytest 测,直接写脚本跑。

 

这是我在真实项目里踩到的一个非常隐蔽的坑,结论非常明确:

代码没问题,问题在测试框架。

 


 

 

问题现象

 

 

在 pytest 里测试一个异步 TokenKeeper(后台轮询 DB):

 

  • asyncio.create_task(self._refresh_loop()) 已执行

  • await asyncio.sleep(50) 明确让出执行权

  • 后台 task 完全不执行

  • 只有在 Ctrl+C 中断 pytest 时,后台 task 才突然开始跑

 

 

同样代码,独立脚本运行一切正常

 


 

 

根本原因(一句话版)

 

 

pytest 接管了 event loop,但不保证后台 task 的调度。

 

在 pytest(pytest-asyncio / anyio)里:

 

  • event loop 是“测试框架控制的”

  • 测试 coroutine 是主任务

  • create_task 创建的后台任务 不属于测试任务树

  • pytest 在某些情况下 不会主动调度这些 task

 

 

所以你看到的是:

 

task 创建了,但永远拿不到执行时间片

 


 

 

为什么 

asyncio.sleep()

 也没用?

 

 

这是个常见误区。

 

sleep() 只是让当前 coroutine让权,

不等于 pytest 会调度后台 task

 

结果就是:

你 sleep 50 秒,后台 task 还是不跑。

 


 

 

一个明确的“踩雷信号”

 

 

如果你发现:

 

  • 后台 task 只在 Ctrl+C 时才继续执行

  • 或测试结束时突然打印一堆后台日志

 

 

可以直接下结论:

 

你在用 pytest 测“服务型异步代码”,方式是错的。

 


 

 

哪些 async 代码不该用 pytest 测

 

 

只要命中任意一条,就别用 pytest:

 

  • asyncio.create_task

  • 无限循环 / poll / keep-alive

  • 后台刷新、守护任务

  • 依赖 event loop 生命周期的逻辑

 

 

这些是“服务”,不是“函数”。

 


 

 

正确做法(强烈建议)

 

 

 

✅ 用独立脚本测试

 

async def main():keeper = AsyncTokenKeeper(...)await keeper.start()token = await keeper.wait_ready()print("token ready:", token)await asyncio.sleep(60)asyncio.run(main())

用:

python scripts/run_async_token_keeper.py

一切正常,逻辑符合直觉。

 


 

 

实战总结(重点)

 

 

  1. pytest ≠ asyncio 运行时

  2. create_task ≠ 一定会执行

  3. 后台 async 服务 ≠ 单元测试对象

  4. 服务型代码要“跑起来看”,不是“断言看”

  5. 怀疑 asyncio 前,先怀疑测试框架

 

 


 

 

最后一句话

 

 

异步服务代码,别迷信测试框架。
脚本才是最诚实的测试方式。

 

pytest 适合测函数,

不适合测“会一直跑的东西”。

 

—— 踩坑记录

 


 


这次的坑有点大,留个机会,供大家参考

http://www.jsqmd.com/news/319195/

相关文章:

  • ChatGLM3-6B新手必看:Streamlit极速对话界面搭建教程
  • GLM-4-9B-Chat-1M镜像免配置:Triton+TensorRT-LLM联合部署低延迟优化方案
  • WAN2.2文生视频镜像多模态协同:结合语音合成生成带配音的完整短视频
  • VibeVoice网页推理教程:JupyterLab一键启动全记录
  • DeepSeek-R1-Distill-Qwen-1.5B快速上手:逻辑推理与代码生成实测
  • Local AI MusicGen调用指南:REST接口使用方法详解
  • 动漫配音神器!IndexTTS 2.0精准对齐画面节奏
  • 51单片机PWM直流电机调速与霍尔测速系统实战:从硬件搭建到多模式控制
  • Hunyuan-MT-7B-WEBUI结合Nginx实现流量分发
  • Qwen-Image-Edit-F2P应用案例:打造个性化电商产品展示图
  • Flowise开源贡献指南:如何为Flowise社区提交PR
  • QWEN-AUDIO企业部署:私有化TTS服务对接内部知识库问答系统
  • MedGemma X-Ray部署教程:多用户并发访问压力测试方法
  • GA/T 1400视图库平台Easy1400实战指南:从设备对接到数据共享
  • 人脸分析系统(Face Analysis WebUI)在考勤场景中的应用指南
  • 从零构建:51单片机IIC协议OLED驱动的底层逻辑与优化技巧
  • Clawdbot整合Qwen3:32B部署案例:高校AI教学平台中多学生Agent沙箱环境搭建
  • EagleEye检测质量保障:内置mAP@0.5:0.95计算模块与自动报表
  • translategemma-27b-it实战案例:专利说明书附图文字→英文法律术语标准化翻译
  • 无需复杂命令!简单几步完成Linux脚本自启配置
  • 一键启动太方便!VibeVoice网页推理真开箱即用
  • OFA-iic/ofa_visual-entailment_snli-ve_large_en企业落地:法律文书图示理解辅助
  • CogVideoX-2b集成方案:嵌入企业内部创作平台的方法
  • mT5分类增强版中文版:从部署到应用的完整指南
  • GLM-TTS高级功能体验报告,流式推理真香
  • ccmusic-database实测:30秒完成音乐风格自动分类
  • 音频太短行不行?1秒到30秒不同长度语音识别结果对比
  • 从硬件到创意:74HC595与LED点阵屏的动画魔法
  • 从故障灯到数据包:解码J1939 DM1报文的工程实践
  • 深度测评继续教育AI论文工具TOP8:选对工具轻松过关