macOS升级Python至3.9.14后代码出现NameError变量未定义问题
问题原因与解决方法
问题原因
你的user_agents变量是在if __name__ == '__main__':代码块内定义的,而Python多进程(multiprocessing.Pool)的子进程启动时会重新导入当前模块,这部分代码不会被执行,因此子进程的内存空间里不存在user_agents变量。
至于3.9.2版本能正常运行,是因为该版本多进程实现存在细节差异,子进程意外继承了主进程的这个变量,但这属于非预期行为。3.9.14修复了这个“漏洞”,严格遵循多进程的内存隔离规则——子进程不会共享主进程在__main__块内定义的变量。
解决方法
方法1:把user_agents作为参数传入check函数
由于pool.map只能传递单个参数,可借助functools.partial将user_agents绑定到check函数上:
from functools import partial def check(url, user_agents): result = None product = Product(url, user_agents) if product.is_connected(): result = product.parse() return result if __name__ == '__main__': user_agents = [] with open('user-agents.txt', encoding='utf8') as f: user_agents = f.readlines() if len(links) > 0: print('Starting with the Pool count = ', PRODUCT_POOL_COUNT) # 绑定user_agents到check函数 check_with_ua = partial(check, user_agents=user_agents) with Pool(PRODUCT_POOL_COUNT) as p: result = p.map(check_with_ua, links) result = list(filter(None, result)) # Remove Empty
方法2:将user_agents定义在全局作用域
把读取user_agents的代码移到if __name__ == '__main__':块外,子进程导入模块时会执行这部分代码,从而获取到变量:
# 全局作用域读取user_agents user_agents = [] with open('user-agents.txt', encoding='utf8') as f: user_agents = f.readlines() def check(url): result = None product = Product(url, user_agents) if product.is_connected(): result = product.parse() return result if __name__ == '__main__': if len(links) > 0: print('Starting with the Pool count = ', PRODUCT_POOL_COUNT) with Pool(PRODUCT_POOL_COUNT) as p: result = p.map(check, links) result = list(filter(None, result)) # Remove Empty
注意:这种方式会让每个子进程都读取一次文件,若文件体积大或读取开销高,不建议使用。
方法3:使用多进程共享变量(适需修改变量的场景)
如果后续需要在子进程中修改user_agents,可通过multiprocessing.Manager创建共享列表:
from multiprocessing import Manager def check(url, user_agents): result = None product = Product(url, user_agents) if product.is_connected(): result = product.parse() return result if __name__ == '__main__': with Manager() as manager: user_agents = manager.list() with open('user-agents.txt', encoding='utf8') as f: user_agents.extend(f.readlines()) if len(links) > 0: print('Starting with the Pool count = ', PRODUCT_POOL_COUNT) check_with_ua = partial(check, user_agents=user_agents) with Pool(PRODUCT_POOL_COUNT) as p: result = p.map(check_with_ua, links) result = list(filter(None, result)) # Remove Empty
内容的提问来源于stack exchange,提问作者Volatil3
相关产品推荐
相关产品推荐

