2017-03-14 112 views
2

我正在處理大型樹並需要增加Python 2.7的遞歸限制。增加Python中的遞歸限制和堆棧大小2.7

使用sys.setrecursionlimit(10000)崩潰我的內核,所以我想我需要增加堆棧大小。

但是我不知道堆棧大小應該有多大。我試過100 MiB像這樣threading.stack_size(104857600),但內核仍然死機。給它1 GiB會引發錯誤。

我還沒有和threading模塊一起工作過,所以當我在腳本的開頭放上面的語句時,我用錯了嗎?我沒有做任何並行處理,一切都在同一個線程中完成。

我的電腦有128 GB物理內存,在Spyder中運行Windows 10,iPython控制檯。

顯示的錯誤很簡單:

內核去世後,重新啓動

罷了。

編輯:

完整的代碼來重現問題。樹的構建被認爲需要相當長的時間,在將整棵樹讀入字典時,內核僅在執行treeToDict()時遞歸執行。也許這個函數的代碼有問題。樹是一種非二叉樹:

import pandas as pd 
import threading 
import sys 
import random as rd 
import itertools as it 
import string 
threading.stack_size(104857600) 
sys.setrecursionlimit(10000) 

class treenode: 
    # class to build the tree 
    def __init__(self,children,name='',weight=0,parent=None,depth=0): 
     self.name = name 
     self.weight = weight 
     self.children = children 
     self.parent = parent 
     self.depth = depth 
     self.parentname = parent.name if parent is not None else '' 

def add_child(node,name): 
    # add element to the tree 
    # if it already exists at the given node increase weight 
    # else add a new child 
    for i in range(len(node.children)): 
     if node.children[i].name == name: 
      node.children[i].weight += 1 
      newTree = node.children[i] 
      break 
    else: 
     newTree = treenode([],name=name,weight=1,parent=node,depth=node.depth+1) 
     node.children.append(newTree) 
    return newTree 

def treeToDict(t,data): 
    # read the tree into a dictionary 
    if t.children != []: 
     for i in range(len(t.children)): 
      data[str(t.depth)+'_'+t.name] = [t.name, t.children[i].name, t.depth, t.weight, t.parentname] 
    else: 
     data[str(t.depth)+'_'+t.name] = [t.name, '', t.depth, t.weight, t.parentname] 
    for i in range(len(t.children)): 
     treeToDict(t.children[i],data) 

# Create random dataset that leads to very long tree branches: 
# A is an index for each set of data B which becomes one branch 
rd.seed(23) 
testSet = [''.join(l) for l in it.combinations(string.ascii_uppercase[:20],2)] 
A = [] 
B = [] 
for i in range(10): 
    for j in range(rd.randint(10,6000)): 
     A.append(i) 
     B.append(rd.choice(testSet)) 
dd = {"A":A,"B":B} 
data = pd.DataFrame(dd) 
# The maximum length should be above 5500, use another seed if it's not: 
print data.groupby('A').count().max() 

# Create the tree 
root = treenode([],name='0') 
for i in range(len(data.values)): 
    if i == 0: 
     newTree = add_child(root,data.values[i,1]) 
     oldses = data.values[i,0] 
    else: 
     if data.values[i,0] == oldses: 
      newTree = add_child(newTree,data.values[i,1]) 
     else: 
      newTree = add_child(root,data.values[i,1]) 
      oldses = data.values[i,0] 

result={} 
treeToDict(root,result) 

PS:我知道了treeToDict()功能是錯誤的,因爲它會覆蓋項目,因爲可以有重複鍵。對於這個錯誤,這個錯誤並不重要。

+1

請向我們展示您得到的實際錯誤,而不是試圖描述它們。你顯然不會從'sys.setrecursionlimit(10000)'崩潰內核。也許與提供關於您正在運行的操作系統的信息有關。 – skyking

+0

添加了一些信息。 – Khris

回答

4

根據我的經驗,您的問題不是堆棧大小,而是算法本身。

根本沒有遞歸可以實現樹遍歷過程。您應該執行基於堆棧的深度/寬度優先搜索算法。 類Python僞代碼可能是這樣的:

stack = [] 
def traverse_tree(root): 
    stack.append(root) 
    while stack: 
    cur = stack.pop() 
    cur.do_some_awesome_stuff() 
    stack.append(cur.get_children()) 

這種做法是令人難以置信的可擴展性,並允許您處理任何樹木。

作爲進一步閱讀,你可以嘗試thisthat

+0

謝謝,我會試試看。 – Khris