65

背景:最小限の構築アルゴリズムを使用して、辞書を表すトライを構築しています。入力リストは4.3Mutf-8文字列で、辞書式に並べ替えられています。結果のグラフは非周期的で、最大深度は638ノードです。スクリプトの最初の行は、を介して再帰制限を1100に設定していますsys.setrecursionlimit()

問題:トライをディスクにシリアル化できるようにしたいので、最初から再構築しなくても(約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

私のデータ構造は比較的単純です。 trie開始状態への参照が含まれ、いくつかのメソッドを定義します。 dfa_stateブールフィールド、文字列フィールド、およびラベルから状態への辞書マッピングが含まれています。

私はの内部動作にあまり精通していませんpickle-私の最大再帰深度は、いくつかのnのトライの深度のn倍以上/等しい必要がありますか?それとも、これは私が知らない何かによって引き起こされた可能性がありますか?

更新: 再帰の深さを3000に設定しても効果がなかったため、この方法は有望ではありません。

更新2: 皆さんは正しかった。デフォルトの再帰制限のために、ピクルスが小さな入れ子の深さを使用することを想定して、私は近視眼的でした。10,000がトリックを行いました。

4

6 に答える 6

43

ドキュメントから:

再帰性の高いデータ構造を選択しようとすると、最大再帰深度を超える可能性があります。この場合、RuntimeErrorが発生します。この制限は、で慎重に上げることができますsys.setrecursionlimit()

トライの実装は単純かもしれませんが、再帰を使用するため、永続データ構造に変換するときに問題が発生する可能性があります。

私の推奨事項は、再帰制限を引き上げ続けて、使用しているデータと使用しているトライの実装に上限があるかどうかを確認することです。

それ以外の場合は、可能であれば、ツリーの実装を「再帰的でない」ように変更するか、データの永続性が組み込まれた追加の実装を作成してみてください(実装でピクルスとシェルフを使用してください)。お役に立てば幸い

于 2010-01-25T19:58:23.177 に答える
11

Pickleはあなたのトライを再帰的に歩く必要があります。Pickleが作業を行うために5レベルの関数呼び出しのみを使用している場合、深さ638のトライではレベルを3000以上に設定する必要があります。

もっと大きな数を試してみてください。再帰の制限は、再帰が無限の穴に落ちた場合にユーザーが長時間待たされるのを防ぐためにあります。

Pickleはサイクルを問題なく処理するので、トライにサイクルがあったとしても問題ありません。

于 2010-01-25T21:28:36.217 に答える
7

resource.setrlimitセグメンテーション違反を防ぐために、スタックサイズも増やす必要があります

だけを使用する場合sys.setrecursionlimitでも、Linuxカーネルで許可されている最大スタックサイズに達すると、セグメンテーション違反が発生する可能性があります。

この値は、Pythonスクリプトでのstacksizeの設定resource.setrlimitで説明したように増やすことができます。

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)

参照:Pythonの最大再帰深度と、それを増やす方法は?

私のデフォルトの最大値は8Mbです。

Ubuntu 16.10、Python2.7.12でテスト済み。

于 2017-01-29T00:05:15.450 に答える
5

構造が実際に非周期的であることを再確認してください。

限界をさらに引き上げてみることができます。プラットフォームに依存する厳しい最大値がありますが、50000を試すのが妥当です。

また、あなたのトライのささいな小さなバージョンをピクルスにしてみてください。3文字の単語が2つしか保存されていないのにピクルスが死んだ場合は、ピクルスではなくトライに根本的な問題があることがわかります。しかし、10k語を保存しようとしたときにのみ発生する場合は、pickleのプラットフォーム制限のせいである可能性があります。

于 2010-01-25T19:58:42.550 に答える
0

私のニーズはやや差し迫っていたので、辞書を.txt形式で保存することでこの問題を解決しました。唯一のことは、ファイルを再度ロードするときに、ファイルを辞書に変換し直す必要があるということです。

import json

# Saving the dictionary
with open('filename.txt', 'w') as file_handle:
    file_handle.write(str(dictionary))

# Importing the .txt file
with open('filename.txt', 'r') as file_handle:
    f = '"' + file_handle.read() + '"'

# From .txt file to dictionary
dictionary = eval(json.loads(f))

これが機能しない場合は、json形式を使用して辞書をエクスポートしてみてください。

于 2017-09-25T22:14:52.913 に答える
0

私にとっては、すべての使用を削除することでimportlib.reload問題が解決しました。で制限を増やす必要すらありませんでしsetrecursionlimitた。

私がどうやってそれを見つけたか知りたいのなら、読み続けてください。

解決策を見つける前に、最初にモデルをCPUに移動すると実際にモデルを保存できることがわかりましたが、評価中にエラーが発生しました(XXXはクラス名であり、重要ではありません)。

PicklingError: Can't pickle <class 'XXX'>: it's not the same object as XXX

それから私はこの答えを見つけました: https ://stackoverflow.com/a/1964942/4295037

しかし、すべての使用を削除した後、importlib.reload最初にCPUデバイスに移動せずにモデルを保存することができました。

于 2020-08-16T21:35:08.350 に答える