dan*_*ben 52 python tree recursion pickle depth
背景:我正在使用最小构造算法构建一个代表字典的trie.输入列表是4.3M utf-8字符串,按字典顺序排序.生成的图形是非循环的,最大深度为638个节点.我的脚本的第一行将递归限制设置为1100 sys.setrecursionlimit()
.
问题:我希望能够将我的trie序列化到磁盘,因此我可以将其加载到内存中而无需从头开始重建(大约22分钟).我曾经尝试都pickle.dump()
和cPickle.dump()
,用文本和二进制协议两种.每次,我得到一个如下所示的堆栈跟踪:
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/pickle.py", line 663, in _batch_setitems
save(v)
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/pickle.py", line 725, in save_inst
save(stuff)
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/pickle.py", line 648, in save_dict
self.memoize(obj)
RuntimeError: maximum recursion depth exceeded
Run Code Online (Sandbox Code Playgroud)
我的数据结构相对简单: trie
包含对开始状态的引用,并定义了一些方法. dfa_state
包含布尔字段,字符串字段和从标签到状态的字典映射.
我对内部工作原理并不十分熟悉pickle
- 我的最大递归深度是否需要大于/等于某些n的trie深度的n倍?或者这可能是由我不知道的其他东西引起的?
更新: 将递归深度设置为3000没有帮助,因此这种途径看起来并不乐观.
更新2: 你们是对的; 由于默认的递归限制,我认为pickle会使用一个小的嵌套深度,因此我是短视的.10,000诀窍.
Joh*_*ooy 10
Pickle确实需要递归地走你的特里.如果Pickle仅使用5级函数调用来完成工作,则深度638的trie将需要设置为超过3000的级别.
尝试一个更大的数字,递归限制实际上只是为了保护用户不必等待太长时间,如果递归落入一个无限的洞.
Pickle处理循环没问题,所以即使你的trie在那里有一个循环也没关系
还必须增加堆栈大小resource.setrlimit
以防止段错误
如果您只使用sys.setrecursionlimit
,如果达到 Linux 内核允许的最大堆栈大小,您仍然可以出现段错误。
这个值可以增加,resource.setrlimit
正如在:在 python 脚本中设置堆栈大小
import pickle
import resource
import sys
print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
max_rec = 0x100000
# May segfault without this line. 0x100 is a guess at the size of each stack frame.
resource.setrlimit(resource.RLIMIT_STACK, [0x100 * max_rec, resource.RLIM_INFINITY])
sys.setrecursionlimit(max_rec)
a = []
# 0x10 is to account for subfunctions called inside `pickle`.
for i in xrange(max_rec / 0x10):
a = [a]
print pickle.dumps(a, -1)
Run Code Online (Sandbox Code Playgroud)
另请参阅:Python 中的最大递归深度是多少,以及如何增加它?
我的默认最大值是 8Mb。
在 Ubuntu 16.10、Python 2.7.12 上测试。
仔细检查您的结构是否确实是非循环的。
您可以尝试进一步提高限制。有一个取决于平台的硬性最大值,但尝试 50000 是合理的。
还可以尝试对 trie 的一个非常小的版本进行腌制。如果 pickle 死掉了,即使它只存储了几个三个字母的单词,那么你就知道你的 trie 存在一些根本问题,而不是 pickle 。但如果它仅在您尝试存储 10k 个单词时发生,那么可能是 pickle 中的平台限制造成的。
归档时间: |
|
查看次数: |
26899 次 |
最近记录: |