SystemError: NULL result Multiprocessing Python
SystemError: NULL result Multiprocessing Python
我正在使用多处理池来训练机器学习器。
每个 LearnerRun 对象都有一个学习者、一个超参数字典、一个名称、其他选项字典中的更多选项、要写入结果的目录的名称、一组要训练的示例 ID(a切片或 numpy 数组),以及一组要测试的示例 ID(也是切片或 numpy 数组)。重要的是,训练和测试数据还没有被读取:ID 集相对较小并且指导后面函数的数据库读取行为。
我调用了 self.pool.apply_async(learner_run.run)
,它以前运行良好。现在池似乎已加载,但从未打印 运行() 函数顶部的打印语句,因此进程实际上并未获得 运行.
我已经追踪了一些关于此的其他 线程 ,发现我可以通过 handler = self.pool.apply_async(learner_run.run)
和 handler.get()
更详细地看到问题。这会打印 "SystemError: NULL result without error in PyObject_Call".
太好了,我可以做到 Google。但是我在 Multiprocessing 的这个问题上所能找到的是,它可能是在将太大而无法 pickle 的参数传递给子进程时引起的。 但是,我显然没有向我的子进程传递任何参数。那么给出了什么?
除了超出分配的内存大小的参数——我有理由相信这不是这里的问题——还有什么可以导致 apply_async 给出空结果?
同样,这在我去度假之前有效并且没有改变。 对其他代码进行哪些类型的更改可能会导致此功能停止工作?
如果我不尝试从处理程序 get()
因此执行不会因错误而停止,内存使用将遵循这种奇怪的模式。
好的,我找到问题了。事实上,我的 LearnerRun 对 Multiprocessing 来说太大了 无法处理。但是它的方式非常微妙,所以我会描述一下。
显然,需要 pickle 的不仅仅是参数;该函数也被腌制,包括其执行将依赖的 LearnerRun
对象(self
)。
LearnerRun 的构造函数获取传递给它的选项字典中的所有内容,并使用 setattr 将所有键和值转换为具有值的成员变量。这本身就很好,但我的同事意识到这留下了几个字符串,需要作为数据库引用并设置 self.trainDatabase = LarData(self.trainDatabase)
和 self.coverageDatabase = LarData(self.coverageDatabase)
,这通常没问题。
Except 这意味着要 pickle class 你必须 pickle 整个数据库!我在健全性检查中发现了这一点,其中只是序列化 LearnerRun 本身以查看 pickle.dumps(learner_run)
会发生什么。我的记忆被淹没了,交换区开始以惊人的速度填满,直到 Whosebug.
那么酸洗到磁盘呢? pickle.dump(learner_run, filename)
也炸了。在我终止之前它达到了 14.3 GiB!
删除这些引用并稍后在需要时调用 LarData 构造函数怎么样?砰。固定的。一切正常。多处理不再给出神秘的 SystemError。
这是second time最近让我很痛苦的泡菜。
我正在使用多处理池来训练机器学习器。
每个 LearnerRun 对象都有一个学习者、一个超参数字典、一个名称、其他选项字典中的更多选项、要写入结果的目录的名称、一组要训练的示例 ID(a切片或 numpy 数组),以及一组要测试的示例 ID(也是切片或 numpy 数组)。重要的是,训练和测试数据还没有被读取:ID 集相对较小并且指导后面函数的数据库读取行为。
我调用了 self.pool.apply_async(learner_run.run)
,它以前运行良好。现在池似乎已加载,但从未打印 运行() 函数顶部的打印语句,因此进程实际上并未获得 运行.
我已经追踪了一些关于此的其他 线程 ,发现我可以通过 handler = self.pool.apply_async(learner_run.run)
和 handler.get()
更详细地看到问题。这会打印 "SystemError: NULL result without error in PyObject_Call".
太好了,我可以做到 Google。但是我在 Multiprocessing 的这个问题上所能找到的是,它可能是在将太大而无法 pickle 的参数传递给子进程时引起的。 但是,我显然没有向我的子进程传递任何参数。那么给出了什么?
除了超出分配的内存大小的参数——我有理由相信这不是这里的问题——还有什么可以导致 apply_async 给出空结果?
同样,这在我去度假之前有效并且没有改变。 对其他代码进行哪些类型的更改可能会导致此功能停止工作?
如果我不尝试从处理程序 get()
因此执行不会因错误而停止,内存使用将遵循这种奇怪的模式。
好的,我找到问题了。事实上,我的 LearnerRun 对 Multiprocessing 来说太大了 无法处理。但是它的方式非常微妙,所以我会描述一下。
显然,需要 pickle 的不仅仅是参数;该函数也被腌制,包括其执行将依赖的 LearnerRun
对象(self
)。
LearnerRun 的构造函数获取传递给它的选项字典中的所有内容,并使用 setattr 将所有键和值转换为具有值的成员变量。这本身就很好,但我的同事意识到这留下了几个字符串,需要作为数据库引用并设置 self.trainDatabase = LarData(self.trainDatabase)
和 self.coverageDatabase = LarData(self.coverageDatabase)
,这通常没问题。
Except 这意味着要 pickle class 你必须 pickle 整个数据库!我在健全性检查中发现了这一点,其中只是序列化 LearnerRun 本身以查看 pickle.dumps(learner_run)
会发生什么。我的记忆被淹没了,交换区开始以惊人的速度填满,直到 Whosebug.
那么酸洗到磁盘呢? pickle.dump(learner_run, filename)
也炸了。在我终止之前它达到了 14.3 GiB!
删除这些引用并稍后在需要时调用 LarData 构造函数怎么样?砰。固定的。一切正常。多处理不再给出神秘的 SystemError。
这是second time最近让我很痛苦的泡菜。