0

Python プログラムを決定論的にしたいのでOrderedDicts、コード全体で広範囲に使用しています。残念なことに、今日メモリ リークをデバッグしているときに、OrderedDicts にカスタム__del__メソッドがあり、サイクルが発生すると収集できないことがわかりました。これに関するドキュメントに警告がないのはかなり残念です。

それで、なにかお手伝いできますか?Python 標準ライブラリに gc とうまく連携する決定論的辞書はありますか? 特にこのような愚かな1行の関数については、自分でロールバックする必要があるのは本当に嫌です。

また、これはバグレポートを提出する必要がありますか? 私は、Python ライブラリの手順と、何がバグと見なされるかについてよく知りません。

編集:これは 2010 年に修正された既知のバグのようです。どうにかして 2.7 の非常に古いバージョンをインストールしたに違いありません。ユーザーが私のような壊れたバージョンを実行している場合に備えて、モンキーパッチを含めるのが最善の方法だと思います。

4

3 に答える 3

2

__del__ メソッドの存在が問題になる場合は、削除してください:

>>> import collections
>>> del collections.OrderedDict.__del__

参照サイクルで OrderedDicts を使用できるようになります。削除するとすぐに OrderedDict がすべてのリソースを解放することを失います。

于 2012-10-01T07:28:02.123 に答える
1

OrderedDictバージョン 2.7 以降のある時点で修正されたバグを追跡したようです。実際にリリースされたバージョンに含まれていない場合は、無視してかまいません。しかし、それ以外の場合は、回避策が必要です。

monkeypatching の代わりに、ドキュメントにリンクされているPython 2.4 以降で実行される同等の OrderedDict レシピをcollections.OrderedDict代わりに使用することをお勧めします(これには余分な はありません)。少なくとも、誰かがやって来て、「これを 2.6 で実行する必要があります。移植するのにどれだけの作業が必要ですか」と言うと、答えは「少し少ない」でしょう…</p> collections.OrderedDict__del__

しかし、さらに2つのポイント:

サイクルを回避するためにすべてを書き直すことは、膨大な労力を要します。

辞書にサイクルがあるという事実は、何か間違ったことをしている危険信号です (通常、キャッシュまたはバックポインターに強い参照を使用しています)。これは、他のメモリの問題につながる可能性があり、おそらく他のメモリの問題につながる可能性があります。バグ。ですから、その努力はいずれ必要になるかもしれません。

何を達成しようとしているのかをまだ説明していません。「決定論的」なことは単なる赤いニシンであると思われるため(特にdicts は実際には決定論的であるため)、最良の解決策はs/OrderedDict/dict/g.

ただし、決定論が必要な場合は、サイクルコレクターに依存することはできません。これは決定論的ではないためです。つまり、ファイナライザーの順序付けなどがすべて非決定論的になります。また、メモリ使用量が非決定論的であることも意味します。100% ではなく、99.999% の確率で目的のメモリ範囲内にとどまるプログラムになる可能性があります。それらの境界が非常に重要である場合、毎回失敗するよりも悪い可能性があります。

一方、辞書の反復順序は指定されていませんが、実際には、CPython と PyPy は、値またはキーの ID (メモリの場所) ではなく、Jython と IronPython が行うこと (動作が異なる Java または .NET コレクションを使用している可能性があります (私はテストしていません)。(そのようなものに基づいてハッシュ テーブルを効率的に反復するにはどうすればよいでしょうか?) idforを使用するオブジェクトでテストして混乱したかもしれませんhashが、ほとんどのオブジェクトは値に基づいてハッシュします。

たとえば、次の簡単なプログラムを見てみましょう。

d={}
d[0] = 0
d[1] = 1
d[2] = 2
for k in d:
  print(k, d[k], id(k), id(d[k]), hash(k))

CPython 2.7、CPython 3.2、および PyPy 1.9 で繰り返し実行すると、キーは常に 0、1、2 の順序で反復されます。id列も毎回同じになる場合があります (プラットフォームによって異なります)。さまざまな方法でそれを修正します — 別の順序で挿入する、値の順序を逆にする、int の代わりに文字列値を使用する、値を変数に割り当ててから、リテラルの代わりにそれらの変数を挿入するなど。列のすべての可能な順序を取得できますがid、キーは毎回同じ順序で反復されます。

反復の順序は予測できません。予測hash(k)するには、Python からアクセスできない情報に依存するバケット インデックスに変換する関数が必要だからです。ただの. hash(k) % self._table_size_ _table_size(これは、挿入と削除のシーケンスの複雑な関数であり、原則として計算できますが、実際に試すのはばかげています。)

しかし、それは決定論的です。毎回同じ順序で同じキーを挿入および削除すると、反復順序は毎回同じになります。

于 2012-10-01T04:51:14.377 に答える