aiodns 因底层基于 c-ares 实现纯异步 DNS 查询,不依赖系统 getaddrinfo,故在高并发下更可控稳定;而 asyncio.getaddrinfo 在 Linux 等平台常同步阻塞,易卡住事件循环,导致延迟突增、CPU 升高。

aiodns 是目前 Python 中最轻量、最直接支持异步 DNS 解析的第三方库,它底层封装了 c-ares,不依赖事件循环的 DNS 实现(比如 asyncio.getaddrinfo 那种走系统调用的方式),因此在高并发、低延迟场景下更可控、更稳定。
为什么不用 asyncio.getaddrinfo 而选 aiodns
虽然 asyncio.getaddrinfo 是标准库函数,但它本质仍是调用操作系统 getaddrinfo() —— 在 Linux 上默认是同步阻塞的(glibc 未启用异步模式时),实际会把事件循环卡住;macOS 和 Windows 表现更不稳定。而 aiodns 绕过系统 resolver,自己用 c-ares 做纯异步 DNS 查询,全程不阻塞。
- 常见错误现象:
asyncio.getaddrinfo在并发 >100 时 CPU 升高、响应延迟突增,甚至触发ResourceWarning: unclosed socket - 性能差异:1000 次域名解析,
aiodns平均耗时约 120ms(并行),asyncio.getaddrinfo可能拉长到 800ms+ 且抖动大 - 兼容性影响:
aiodns需要额外安装c-aresC 库(Linux/macOS 用包管理器装,Windows 用户建议用预编译 wheel)
安装与基础用法:避开 wheel 缺失和 event loop 冲突
直接 pip install aiodns 在某些环境(尤其是 Windows + Python 3.12+ 或 M1 Mac)可能失败,因为缺少 c-ares 编译环境或 wheel 不匹配。
- 推荐安装方式:
pip install aiodns --only-binary=aiodns(强制用二进制包) - 若报
RuntimeError: This event loop is already running,说明你是在 Jupyter 或已启动的 loop 里调用 —— 改用asyncio.create_task()提交,不要直接asyncio.run() -
Resolver实例必须绑定到当前运行的 event loop,不能跨 loop 复用;建议每个协程内 new 一个,或作为 session 级单例管理
批量解析时如何控制超时与重试
aiodns 默认无超时,一次失败就抛异常,不适合生产环境的大规模探测。
立即学习“Python免费学习笔记(深入)”;
- 必须显式传
timeout=3.0和tries=2参数,否则 DNS 超时可能长达 30 秒(取决于系统配置) - 不要依赖
asyncio.wait_for包裹单个query调用 —— 它无法中断c-ares底层请求,只会等到底层返回再抛 CancelledError - 正确做法:在
Resolver初始化时设全局timeout,再用asyncio.gather(..., return_exceptions=True)批量收拢结果 - 示例片段:
resolver = aiodns.DNSResolver(timeout=2.5, tries=2) tasks = [resolver.query(host, 'A') for host in hosts] results = await asyncio.gather(*tasks, return_exceptions=True)
记录类型、DNS 服务器与 fallback 切换的实际限制
aiodns 支持 A、AAAA、CNAME、MX、TXT、NS 等主流类型,但不支持 DNSSEC 验证、不支持自定义 EDNS 选项,也无法像 dnspython 那样构造原始查询包。
- 指定上游 DNS 服务器:用
nameservers=['8.8.8.8', '1.1.1.1']初始化Resolver,但注意它不自动做健康检查 —— 一个服务器挂了,所有请求都会 fallback 到下一个,且无重试间隔控制 - 真实 fallback 场景(如内网 DNS 不稳定):得自己封装一层,比如先发请求到内网 DNS,
asyncio.wait_for包裹后 catchaiodns.error.DNSError,再切到公网 DNS 重试 - 反向解析(PTR)可用,但输入必须是合法 IP 字符串(如
'192.168.1.1'),不能是压缩格式或带掩码
真正难处理的不是并发量,而是 DNS 响应的不可预测性:TTL 不一致、缓存污染、运营商劫持、EDNS 截断。用 aiodns 只是把“查得快”这件事做对了,但查回来的结果是否可信、是否要二次验证(比如比对 A/AAAA 记录一致性)、是否需配合 HTTP HEAD 探活——这些得在上层逻辑里补全,而不是指望库自动解决。


















