Ubuntu下Python multiprocessing僵尸进程及Reactor报错如何解决?
初始手动管理Process出现僵尸进程的解决方案
出现僵尸进程的核心原因是你只在所有任务分发完成后才统一执行join()回收进程,运行过程中替换已结束进程时没有回收旧进程的退出状态,导致结束的子进程变为僵尸进程残留。可通过以下方式预防:
- 替换非存活进程前先执行
join()回收资源,修改process_x函数中的进程创建逻辑:if not (list_process[i] and list_process[i].is_alive()): # 先回收已结束的旧进程 if list_process[i] is not None: list_process[i].join() list_process[i] = Process(target=launch_crawler, args=(SalesSpider, urls_lst.pop(0)), daemon=True) list_process[i].start() break - 创建进程时添加
daemon=True参数,设置子进程为守护进程,主进程退出时会自动强制回收所有子进程,避免残留。 - 移除手动
del对象和gc.collect()调用,Python自动内存管理足够应对该场景,频繁主动调用GC反而会降低运行性能。 - 降低进程数量,Scrapy本身是异步IO框架,单进程即可处理大量并发请求,开120个进程会导致严重的上下文切换和资源竞争,反而降低稳定性,建议进程数设置为CPU核心数的1~2倍即可。
Pool方案出现ReactorNotRestartable错误的解决方案
该错误的原因是multiprocessing.Pool默认会复用工作进程,Twisted的Reactor是单例模式,同一个进程内只能启动一次,第一个任务跑完Reactor停止后,第二个任务复用同一个进程再次启动Reactor就会触发该报错。可通过以下方式解决:
- 最简单的方案是设置工作进程只处理1个任务就销毁,创建Pool时添加
maxtasksperchild=1参数:
每个工作进程只跑一个任务就退出,新任务会用全新的进程启动Reactor,不会出现重启问题。pool = multiprocessing.Pool(processes, maxtasksperchild=1) - 更高性能的方案是每个工作进程仅启动一次Reactor,批量处理多个任务,修改任务函数为接收一批seller统一执行:
调用时提前将seller列表按批次拆分后传入Pool即可,每个进程仅启动一次Reactor,避免重复创建的开销。def launch_crawler_batch(sellers_batch): process = CrawlerProcess(crawler_settings) for seller in sellers_batch: formated_seller = format_target(seller[1]) if formated_seller: process.crawl(SalesSpider, seller[0], formated_seller, seller[2]) process.start(stop_after_crawl=True) - 最优方案是直接使用Scrapy自带的并发能力,调整
CONCURRENT_REQUESTS参数提高单进程并发数,不需要额外引入多进程管理,架构更简单稳定性也更高。
内容的提问来源于stack exchange,提问作者IndiaSke
相关产品推荐
相关产品推荐

