ComfyUI 启动卡死无任何报错:一次 Windows 回环连接被安全软件拦截的完整排查
摘要:ComfyUI(秋叶启动器 2.9.1)启动后进度条不动、日志停在
comfy-kitchen version再无输出、无报错无堆栈、端口 8188 始终不通。本文记录一次完整的定位过程:用 py-spy 抓栈 → 发现卡在socket.socketpair()→ 最小化复现 → 差分对比定位到"只有特定 python.exe 被拦截" → 确认是本机安全软件的网络过滤驱动阻断了 127.0.0.1 回环 TCP。附完整排查脚本和可复用清单。
关键词:ComfyUI 启动卡死、Windows 回环连接、socketpair 阻塞、asyncio ProactorEventLoop、py-spy、安全软件网络过滤、WinError 121
一、环境与现象
| 项目 | 值 |
|---|---|
| 系统 | Windows 11(NT 10.0.26200) |
| 启动器 | ComfyUI 秋叶 Launcher 2.9.1.417 |
| ComfyUI | v0.33.2(2026-08-18 版本) |
| Python | 3.13.11(便携版,D:\ComfyUI-aki-v3.2\python) |
| PyTorch | 2.13.0+cu130 |
| GPU | RTX 3060 12GB |
| 端口 | 8188 |
现象:
-
启动器点击"启动"后一直转圈,永远不弹出 WebUI;
-
日志最后三行永远是这三句,之后没有任何输出,也没有异常:
[INFO] ComfyUI version: 0.33.2
[INFO] comfy-aimdo version: 0.4.13
[INFO] comfy-kitchen version: 0.2.31 -
当天 09:00 / 09:05 / 09:10 三次启动,
comfyui.log、comfyui.prev.log、comfyui.prev2.log字节数完全一样 (5743 B)------说明是确定性卡死,不是偶发网络抖动。
二、第一轮排查:排除所有"看起来很像"的嫌疑
在看日志之前,我先把最容易误判的几个方向全部验证了一遍。
2.1 嫌疑一:自定义节点加载卡死(最容易误判)
日志停在 comfy-kitchen version,而 ComfyUI 的加载顺序中,下一步就是 init_extra_nodes() 遍历 custom_nodes/。直觉是某个节点在 import 时卡住了(比如 Impact-Pack 下载模型、controlnet_aux 下载权重)。
但证据不支持 :如果是节点加载慢,日志里会出现 ### Loading: <节点名>;而三次日志都连一行 ### Loading 都没有,说明根本没进入节点加载阶段。
2.2 嫌疑二:外部网络问题
诊断文件里记录了系统配置过网络代理。实测外网 HTTPS 镜像站访问正常、耗时不足 1 秒。
这些都是干扰项。因为 ComfyUI 的卡点在日志打印完之后立刻发生,且后面会验证:本机回环都不通,和外网连通性无关。
2.3 嫌疑三:内存 / 显存不足
16 GB 内存、仅 7.1 GB 可用,看着有点紧,但卡死进程常驻 883 MB,没有 swap 抖动迹象,且 NORMAL_VRAM 已正常设置。排除。
三、第二轮:py-spy 抓栈,一击致命
日志不说话,就让进程自己说。安装 py-spy(独立诊断工具,不污染业务依赖,用完可卸):
bash
"D:\ComfyUI-aki-v3.2\python\python.exe" -m pip install py-spy -i https://pypi.tuna.tsinghua.edu.cn/simple
然后另起一个命令行手动复现一次 (python -u main.py,-u 关闭输出缓冲),等它卡住后抓栈:
bash
"D:\ComfyUI-aki-v3.2\python\Scripts\py-spy.exe" dump --pid <卡住的PID>
输出(已精简):
Thread (idle): "MainThread"
accept (socket.py:295)
_fallback_socketpair (socket.py:627)
_make_self_pipe (asyncio\proactor_events.py:786)
__init__ (asyncio\proactor_events.py:639)
__init__ (asyncio\windows_events.py:316)
new_event_loop (asyncio\events.py:734)
new_event_loop (asyncio\events.py:837)
start_comfyui (main.py:513)
<module> (main.py:584)
真相大白 :主线程卡在 accept(),调用链是
start_comfyui
→ asyncio.new_event_loop() # Windows 用 ProactorEventLoop
→ ProactorEventLoop.__init__
→ _make_self_pipe() # 事件循环自唤醒管道
→ socket.socketpair() # Windows 没有原生 socketpair
→ _fallback_socketpair() # 回退实现:真实回环 TCP
→ socket.accept() # ← 永久阻塞
为什么 socketpair() 会走真实 TCP?
Windows 的 Winsock 没有 AF_UNIX,CPython 的 socket.socketpair() 在 Windows 上是回退实现:
- 建一个 socket,
bind(('127.0.0.1', 0))+listen(1); - 再建一个 socket
connect(('127.0.0.1', port)); - 服务端
accept()收下这条连接,得到一对双向管道。
只要回环 TCP 握手被拦,connect() 和 accept() 就会错位,且这一路径没有任何超时保护------永久阻塞。
四、最小化复现:两行命令定性
python
# 测试 1:直接验证 socketpair
import socket
a, b = socket.socketpair() # ← 15 秒无输出,被 timeout 杀掉
# 测试 2:验证原始回环 TCP
s = socket.socket(); s.bind(('127.0.0.1', 0)); s.listen(1)
p = s.getsockname()[1]
c = socket.create_connection(('127.0.0.1', p), timeout=5)
# TimeoutError: timed out
回环连接确实超时。注意这里的诡异现象 :连接一个没人监听 的端口会立刻 ConnectionRefused(SYN 正常送达、被栈回 RST),但连接一个正在监听 的端口却超时------说明过滤发生在握手后半段,是典型的有状态包过滤特征,不是路由/网卡故障。
差分对比(关键一步)
| 测试对象 | 回环自连 |
|---|---|
C:\Python314\python.exe(系统 Python) |
✅ OK |
D:\ComfyUI-aki-v3.2\python\python.exe |
❌ 超时 |
| 把 ComfyUI 的 python.exe 改名再跑 | ❌ 仍然超时 |
结论 :不是系统级故障,是按可执行文件维度的过滤。
五、定位元凶:安全软件的过滤驱动
系统里干这事的只可能是带网络过滤驱动的安全软件。用 driverquery 查内核驱动,确认本机某主流安全软件(腾讯系)的过滤驱动处于运行状态:
bash
driverquery /fo csv | grep -iE "QQSysMonX64|TSSysKit|TcHardWare|QMUdisk"
"QMUdisk", "tencent QMUdisk", "Kernel"
"QQSysMonX64", "QQSysMonX64", "File System"
"TSSysKit", "TSSysKit", "Kernel"
"TcHardWare", "TcHardWare", "Kernel"
同时托盘和后台服务都在运行(QQPCTray.exe 托盘 + QQPCRTP.exe 服务进程)。
注意 :Winsock 目录(LSP)是干净的,只有微软自己的 mswsock.dll;Windows 防火墙也没有任何 Block 规则、没有针对 python 的规则。也就是说,拦截发生在更底层的 WFP 过滤驱动层,常规排查手段看不到。
验证:调整安全软件防护后
通过安全软件设置关闭进程网络防护(或结束其后台服务进程)后重测:
socket.socketpair() # ✅ OK
127.0.0.1 自连 # ✅ OK
回环立刻恢复,ComfyUI 也随即越过了原来的卡点:
[INFO] ### Loading: ComfyUI-Impact-Pack (V8.28.3)
[INFO] ### Loading: ComfyUI-Manager (V3.39)
[INFO] ### ComfyUI Version: v0.33.2 | Released on '2026-08-17'
根因确认 :安全软件的网络过滤驱动拦截了 D:\ComfyUI-aki-v3.2\python\python.exe 的 127.0.0.1 回环连接,导致 asyncio 事件循环创建时永久阻塞。
六、解决方案
按优先级:
| 方案 | 操作 | 适用场景 |
|---|---|---|
| ① 调整安全软件防护 | 在安全软件设置里关闭"网络安全/进程网络防护"类开关,或彻底退出(含后台服务进程),立即验证 | 快速验证,立即可用 |
| ② 加白名单 | 安全软件 → 设置 → 信任/白名单,加入 D:\ComfyUI-aki-v3.2\python\python.exe(必要时把整个 D:\ComfyUI-aki-v3.2\ 加进去) |
想长期共存 |
| ③ 重启系统后再测 | 过滤驱动驻留内核,重启后状态最干净 | 反复复发时 |
| ④ 临时绕开(不推荐长期使用) | 给 python.exe 换路径/改名,本例实测无效 |
------ |
实测踩坑:只点托盘"退出"可能不够。托盘进程退了,后台服务进程仍在运行,拦截照旧,需要通过安全软件设置彻底关闭相关防护,或重启机器。
七、踩坑清单(重点)
-
日志截断点极具欺骗性 :日志停在
comfy-kitchen version,看起来像"下一步加载节点卡死",实际卡在更后面的事件循环创建。没有### Loading:就是线索。 -
不要用"猜节点"的方式排错:挨个禁用 custom_nodes 试是最慢的路。py-spy 一条命令就能看到真实调用栈。
-
Windows 上
socket.socketpair()是回退实现 ,走真实回环 TCP 且无超时。任何 asyncio 程序(ComfyUI、Gradio、FastAPI 等)都可能以"启动无响应"的形式暴露这个问题。 -
"端口没监听→立刻 refused"不等于"回环正常"。要专门测"连一个正在 listen 的端口"。
-
差分对比比看配置更快:同一台机器上换一个 python 跑同一个脚本,5 秒就能判定是系统级还是进程级问题。
-
安全软件的"退出"要退到服务进程为止,不是退出托盘。
-
Winsock / 防火墙干净 ≠ 没有拦截 :WFP 驱动层过滤,
netsh winsock show catalog和netsh advfirewall都看不见。 -
Git Bash 下
taskkill要加前缀:bashMSYS_NO_PATHCONV=1 taskkill /PID 12345 /F # 否则 /PID 会被路径转换成 //PID,报"无效参数" -
pip 被中断会留下残包 :一次被超时打断的 pip 安装后,
site-packages/rich/目录不完整,启动时报ModuleNotFoundError: No module named 'rich.console'。修复:bashpython -m pip install --force-reinstall "rich==14.2.0" -i https://pypi.tuna.tsinghua.edu.cn/simple -
诊断工具用完记得卸(可选):
bashpython -m pip uninstall -y py-spy -
排查期间不要往业务目录里放临时文件 :本次做"改名对照实验"时生成的
testloop.exe副本,事后需从回收站找回。做实验前先确认目标路径,删除操作后检查回收站确认无误。
八、可复用排查脚本
保存为 check_loopback.py,任何"程序启动卡住、无报错"的场景先跑它:
python
import socket, sys, time
PY = sys.executable
def t(name, fn):
t0 = time.time()
try:
fn()
print(f"[OK] {name} ({time.time()-t0:.2f}s)")
return True
except Exception as e:
print(f"[FAIL] {name}: {type(e).__name__} {e}")
return False
def loopback():
s = socket.socket(); s.bind(('127.0.0.1', 0)); s.listen(1)
port = s.getsockname()[1]
try:
c = socket.create_connection(('127.0.0.1', port), timeout=5); c.close()
finally:
s.close()
def socketpair():
a, b = socket.socketpair(); a.close(); b.close()
print(f"Python: {PY}\n")
ok1 = t("127.0.0.1 回环自连", loopback)
ok2 = t("socket.socketpair()", socketpair)
if not (ok1 and ok2):
print("\n>>> 回环连接异常:优先怀疑安全软件的进程级网络过滤。")
print(">>> 处理:加白名单 / 调整防护设置后重启验证。")
sys.exit(1)
print("\n回环正常,卡死原因在别处------改用 py-spy dump 抓栈。")
排查顺序建议:
启动卡住、无报错
├─ 跑 check_loopback.py
│ ├─ 失败 → 安全软件拦截回环(本文场景)
│ └─ 成功 → py-spy dump --pid <PID> 看真实调用栈
├─ 日志停在最后一行 → 那一行只是"最后打印的内容",不等于卡点
└─ 多次复现日志字节数一致 → 确定性死锁,直接抓栈,别猜
九、小结
这次卡死的本质:ComfyUI 在创建 asyncio 事件循环时,Windows 的 socket.socketpair() 回退实现需要建立一次 127.0.0.1 回环连接,而这次连接被安全软件的 WFP 驱动静默丢弃,且该路径没有超时,于是进程在 accept() 上永久阻塞。
三个值得记住的点:
- 没有报错的卡死,抓栈比看日志快 10 倍------py-spy 是 Windows 上最省事的死锁定位工具;
- 回环连接是很多程序的隐性依赖,被拦时表现千奇百怪(启动卡死、本地服务连不上、本地代理失效),但根因往往只有一个;
- 安全软件的"退出"要退到服务进程为止,否则你会以为排除了,其实什么都没变。