Python多线程下载内存占用过高问题及优化方案咨询
解决Python多线程下载内存耗尽的问题
嘿,看来你碰到Python多线程下载的经典内存泄漏问题了!咱先拆解下可能的问题所在,再给你几个能稳定跑几小时都不爆内存的靠谱方案。
先捋捋内存泄漏的可能原因
- 你的
worker是无限循环逻辑,虽然用了jq.task_done(),但如果download_stuff函数里没正确释放资源(比如打开的文件没关闭、网络连接没断开、下载的数据存在全局变量里没清理),时间一长内存肯定会被占满。 - 另外,如果队列
jq里的任务添加速度远快于处理速度,堆积的item也会占用内存,但你说运行数小时才耗尽,更大概率是前者的资源泄漏问题。
靠谱的替代方案
方案1:用concurrent.futures.ThreadPoolExecutor(首推)
这个是Python3.2+自带的模块,线程管理更高效,还能自动回收线程资源,避开手动管理队列的各种坑。
示例代码:
from concurrent.futures import ThreadPoolExecutor import gc def download_stuff(item): # 核心注意点:下载完成后务必释放所有资源 # 比如用requests下载时,用with语句自动关闭连接: # with requests.get(url) as resp: # with open('file', 'wb') as f: # f.write(resp.content) # 处理数据后不要留全局大对象,及时清理临时变量 pass def main(): input_list = [1,2,3,4,5,...] # 你的任务列表 # 线程数根据网络带宽和机器配置调整,一般10-20个足够 with ThreadPoolExecutor(max_workers=15) as executor: # map方法会自动分配线程处理任务,完成后自动回收资源 executor.map(download_stuff, input_list) # 极端情况下手动触发垃圾回收(可选) gc.collect() if __name__ == "__main__": main()
为什么这个能避免内存问题?
ThreadPoolExecutor会自动管理线程生命周期,任务完成后线程会被回收,不会一直占用资源。with语句会自动关闭executor,彻底清理所有线程相关资源。- 如果需要动态添加任务,也可以用
executor.submit()配合concurrent.futures.as_completed(),处理完一个任务就回收对应资源。
方案2:优化原有的队列+线程方案
如果你不想换模块,那得给原代码加上内存防护:
import threading import queue import gc # 设置队列最大长度,避免任务无限堆积占内存 jq = queue.Queue(maxsize=20) def worker(): while True: item = jq.get() try: download_stuff(item) finally: jq.task_done() # 每次任务完成后手动清理垃圾,释放未被回收的资源 gc.collect() # 启动守护线程,主进程退出时自动结束线程 for _ in range(10): t = threading.Thread(target=worker, daemon=True) t.start() # 添加任务,队列满时会自动阻塞,防止任务堆积 input_list = [1,2,3,...] for item in input_list: jq.put(item) jq.join()
关键优化点:
- 给队列设置
maxsize,任务满了就暂停添加,避免内存被堆积的任务占满。 - 用
daemon=True设置守护线程,防止主进程退出后线程还在后台占用资源。 - 在
finally块里确保task_done()执行,并且手动触发垃圾回收。
必做的内存检查
- 重点排查
download_stuff函数:有没有用open()后没关闭文件?有没有把大文件内容存在列表/字典里没清空? - 可以用
tracemalloc模块定位内存泄漏点:
import tracemalloc tracemalloc.start() # 运行你的下载代码 snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') print("[Top 10内存占用点]") for stat in top_stats[:10]: print(stat)
这样就能看到哪行代码占用内存最多,针对性优化。
内容的提问来源于stack exchange,提问作者Ashley A.
相关产品推荐
相关产品推荐

