Ubuntu下Python多线程爬虫报Too many open files [eventpoll]排查求助
嘿,这个问题我之前在多线程爬虫项目里踩过类似的坑!结合你提到的eventpoll条目和跨平台差异,给你几个逐步排查的思路:
1. 优先检查requests Session的复用与关闭逻辑
这是最常见的根源——Linux下文件描述符(FD)的回收机制比Windows更“严谨”,如果每个请求都新建requests.Session或者用完没正确关闭,这些Session持有的网络连接FD会被长期占用,积累到一定数量就触发Too many open files。
- 建议线程内复用Session:每个线程初始化一个Session,全程复用,线程结束时调用
session.close();或者用with上下文管理器确保自动关闭:with requests.Session() as session: response = session.get(url) # 处理响应 - 避免在循环/每个任务里反复创建Session,这会导致大量冗余的连接FD无法及时释放。
2. 排查线程资源泄漏
如果线程没有正常退出,它持有的所有资源(包括网络FD)都不会被回收:
- 用
ps -T -p <你的进程PID>查看线程数量是否持续增长,如果是,说明有僵尸线程或者线程池未正确关闭。 - 检查你的线程池配置:比如用
concurrent.futures.ThreadPoolExecutor时,是否在任务全部完成后调用了executor.shutdown()?或者是否存在无限循环的线程任务没设置退出条件?
3. 验证系统文件描述符限制
Ubuntu默认的进程最大打开文件数可能偏低(通常默认是1024),可以先确认:
- 用
ulimit -n看当前shell的限制,用cat /proc/<你的PID>/limits查看目标进程的实际限制。 - 如果限制确实太低,可以临时调高(比如
ulimit -n 4096)测试,但这只是治标,核心还是要找到泄漏根源,不然调得再高最终还是会爆。
4. 配置requests的连接池参数
requests依赖urllib3的连接池,默认的连接数设置可能导致大量空闲连接占用FD:
- 显式设置连接池的最大连接数,限制空闲连接的数量:
from requests.adapters import HTTPAdapter session = requests.Session() # 限制每个域名的连接数 adapter = HTTPAdapter(pool_connections=10, pool_maxsize=10) session.mount('http://', adapter) session.mount('https://', adapter) - 也可以尝试关闭keep-alive来测试:
session.get(url, headers={'Connection': 'close'}),如果问题消失,说明是空闲keep-alive连接没被正确回收。
5. 用工具定位FD泄漏点
如果以上思路都没找到问题,可以用工具精准追踪:
- 用
strace -p <你的PID> -e open,close实时查看进程的FD打开/关闭操作,看哪些FD只打开没关闭。 - 用
py-spy top -p <你的PID>分析Python进程的调用栈,观察哪些线程在持续创建网络连接但未释放。 - 结合
lsof -p <你的PID> | grep eventpoll的结果,找到这些FD对应的线程ID,再用pstack <你的PID>查看线程栈,定位到具体的代码逻辑。
最后补充
Windows的FD回收机制更宽松,很多隐性的资源泄漏不会立刻暴露,但Linux下会严格累积,所以跨平台出现差异很正常。优先从Session复用、线程生命周期、连接池配置这几个方向入手,大概率能解决问题。
内容的提问来源于stack exchange,提问作者Susheng
相关产品推荐
相关产品推荐

