我正在使用多处理池运行一段代码。该代码在一个数据集上工作,在另一个数据集上失败。显然,问题是数据驱动的 - 话虽如此,我不清楚从哪里开始故障排除,因为我收到的错误如下。任何起点提示都将是最有帮助的。 两组数据都是使用相同的代码准备的 - 所以我不希望有区别 - 但我在这里。
另请参阅罗伯特的评论 - 我们在操作系统和 python 版本 3.6(我有 3.4,他有 3.6)和完全不同的数据集上有所不同。然而,错误与python代码中的行相同。
我的怀疑:
- 正在强制执行的每个内核都有内存限制。 有
一段时间后,该过程实际上会收集 - 发现该过程尚未结束并放弃。
线程线程 9 中的异常:
回溯(最近一次调用):
文件 "C:\Program Files\Python\WinPython-64bit-3.4.4.4Qt5\python-3.4.4.amd64\lib\threading.py",第 911 行,_bootstrap_inner self.run()
文件 "C:\Program Files\Python\WinPython-64bit-3.4.4.4Qt5\python-3.4.4.amd64\lib\threading.py",第 859 行,正在运行 self._target(*self._args, **self._kwargs)
文件 "C:\Program Files\Python\WinPython-64bit-3.4.4.4Qt5\python-3.4.4.amd64\lib\multiprocessing\pool.py",第 429 行,_handle_results 任务 = 获取()
文件 "C:\Program Files\Python\WinPython-64bit-3.4.4.4Qt5\python-3.4.4.amd64\lib\multiprocessing\connection.py",第 251 行,在 recv 中 return ForkingPickler.loads(buf.getbuffer())
类型错误:init() 缺少 1 个必需的位置参数:"消息">
我认为问题是langdetect悄悄地在这里宣布了一个隐藏的全局探测器工厂 https://github.com/Mimino666/langdetect/blob/master/langdetect/detector_factory.py#L120:
def init_factory():
global _factory
if _factory is None:
_factory = DetectorFactory()
_factory.load_profile(PROFILES_DIRECTORY)
def detect(text):
init_factory()
detector = _factory.create()
detector.append(text)
return detector.detect()
def detect_langs(text):
init_factory()
detector = _factory.create()
detector.append(text)
return detector.get_probabilities()
根据我的经验,这种事情可能会导致多处理出现问题,因为它与多处理尝试跨进程共享内存中的资源以及管理工作线程和主进程中的命名空间的方式相冲突,尽管在这种情况下的确切机制对我来说是一个黑匣子。我通过在池初始化函数中添加对init_factory
函数的调用来修复它:
from langdetect.detector_factory import init_factory
def worker_init_corpus(stops_in):
global sess
global stops
sess = requests.Session()
sess.mount("http://", HTTPAdapter(max_retries=10))
stops = stops_in
signal.signal(signal.SIGINT, signal.SIG_IGN)
init_factory()
仅供参考:"sess"逻辑是为每个工作线程提供一个用于请求的 http 连接池,以解决将该模块与多处理池一起使用时的类似问题。如果不这样做,工作线程将通过父进程备份其所有 http 通信,因为默认情况下,这是隐藏的全局 http 连接池所在的位置,然后一切都非常缓慢。这是我遇到的问题之一,让我怀疑这里有类似的原因。
此外,为了进一步减少潜在的混淆:stops
用于向映射函数提供我正在使用的停用词列表。signal
调用是强制池在被用户中断 (ctrl-c) 击中时很好地退出。否则,它们经常会成为孤儿,并在父进程死亡后继续前进。
然后我的池初始化如下:
self.pool = mp.Pool(mp.cpu_count()-2, worker_init_corpus, (self.stops,))
我还将我的呼叫detect
包装在一个尝试/捕获LangDetectExeception
块中:
try:
posting_out["lang"] = detect(posting_out["job_description"])
except LangDetectException:
posting_out["lang"] = "none"
但这并不能自行解决它。非常有信心初始化是修复程序。
感谢罗伯特 - 专注于 lang 检测产生了这样一个事实,即我的一个文本条目可能是空
的语言检测异常:文本中没有功能
菜鸟错误 - 可能是由于编码错误 - 过滤掉这些错误后重新运行 - 将使您(罗伯特)保持发布。
我在代码中的某个地方抛出了一个自定义异常,它在我的大部分进程中(在池中)被抛出。我大约 90% 的流程进入睡眠状态,因为这种异常发生在其中。但是,我没有得到正常的回溯,而是得到了这个神秘的错误。不过,我的是在Linux上。
为了调试它,我删除了池并按顺序运行代码。