順序付けられた辞書であるcollections
モジュールの OrderedDict を参照しています。
注文可能という機能が追加されている場合、多くの場合必要がないかもしれませんが、それでも不利な点はありますか?遅いですか?機能が不足していますか?不足しているメソッドはありませんでした。
要するに、なぜすべきではないのですか通常の辞書の代わりにこれを常に使用しますか?
OrderedDict
はdict
のサブクラスであり、キーが追加される順序を追跡するためにより多くのメモリが必要です。これは簡単なことではありません。実装により、2番目のdict
が背後に追加され、すべてのキーの二重リンクリスト(順序を記憶する部分)と多くのweakrefプロキシが追加されます。 lot遅くはありませんが、プレーンdict
を使用する場合に比べてメモリが少なくとも2倍になります。
しかし、それが適切であれば、それを使用してください!それがそこにある理由です:-)
基本辞書は、キーを値にマッピングする通常の辞書です-「順序付け」されていません。 _<key, value>
_ペアが追加されると、key
がリストに追加されます。リストは順序を記憶する部分です。
しかし、これがPythonリストの場合、削除キーの場合、O(n)
時間が2回かかります:O(n)
時間リスト内のキー、およびリストからキーを削除するO(n)
時間。
したがって、代わりに二重にリンクされたリストです。これにより、キー定数(O(1)
)が削除されます。しかし、キーに属する二重にリンクされたリストノードを見つける必要があります。その操作をO(1)
時間にするために、2番目の-非表示-dictは、二重リンクリスト内のノードにキーをマップします。
したがって、新しい_<key, value>
_ペアを追加するには、ペアを基本辞書に追加し、キーを保持する新しい二重リンクリストノードを作成し、その新しいノードを二重リンクリストに追加し、キーをその新しいリンクにマッピングする必要があります隠された辞書のノード。作業時間は2倍以上ですが、全体でO(1)
(予想されるケース)の時間です。
同様に、存在するキーを削除すると、2倍以上の作業になりますが、全体の予想時間はO(1)
です。非表示のdictを使用して、キーの二重リンクリストノードを見つけ、リストからそのノードを削除します。両方の辞書からキーを削除します。
等、それは非常に効率的です。
マルチスレッド
特に同期ポイントとして、ロックなしで複数のスレッドからディクショナリにアクセスする場合。
バニラのdict操作はアトミックであり、Pythonで拡張された型はアトミックではありません。
実際、私はOrderedDictがスレッドセーフ(ロックなし)であるとさえ確信していませんが、非常に注意深くコーディングされ、再入可能性の定義を満たす可能性を無視することはできません。
小悪魔
これらの辞書を大量に作成した場合のメモリ使用量
すべてのコードがこれらの辞書を変更する場合のCPUの使用
通常の辞書の代わりにこれを常に使用するべきではないのはなぜですか
Python 2.7、normal OrderedDict
を使用すると、参照サイクルが作成されます。したがって、OrderedDict
では、メモリを解放するためにガベージコレクターを有効にする必要があります。はい、cPythonではガベージコレクターがデフォルトでオンになっていますが、無効にしています その用途があります 。
例えばcPython 2.7.14
_from __future__ import print_function
import collections
import gc
if __== '__main__':
d = collections.OrderedDict([('key', 'val')])
gc.collect()
del d
gc.set_debug(gc.DEBUG_LEAK)
gc.collect()
for i, obj in enumerate(gc.garbage):
print(i, obj)
_
出力
_gc: collectable <list 00000000033E7908>
gc: collectable <list 000000000331EC88>
0 [[[...], [...], 'key'], [[...], [...], 'key'], None]
1 [[[...], [...], None], [[...], [...], None], 'key']
_
空のOrderedDict
(d = collections.OrderedDict()
)を作成して何も追加しなかった場合、またはclear
メソッドを呼び出して明示的にクリーンアップしようとした場合でも( _del d
_)の前のd.clear()
でも、自己参照リストが1つ取得されます。
_gc: collectable <list 0000000003ABBA08>
0 [[...], [...], None]
_
this commit が___del__
_メソッドを削除して、OrderedDict
が収集不能なサイクルを引き起こす可能性を防ぐために、これは事実であると思われます。そのコミットの変更ログに記載されているように:
問題#9825 :collections.OrderedDictの定義から__del__を削除しました。これにより、ユーザーが作成した自己参照の順序付き辞書が永久に収集できないGCガベージになるのを防ぎます。欠点は、__ del__を削除すると、refcntがゼロになったときにすぐにメモリを解放するのではなく、内部の二重リンクリストがGCの収集を待つ必要があることです。
Python 3では、同じ問題の fix は異なる方法で作成され、weakrefプロキシを使用して循環を回避していることに注意してください。
問題#9825:collections.OrderedDictの定義で__del__を使用すると、ユーザーが自己参照型の順序付き辞書を作成できるようになり、永続的に収集できないGCガベージになった。参照サイクルが最初に作成されないように、weakrefプロキシを使用するPy3.1アプローチを復活させました。
Python 3.7なので、すべての辞書が順序付けられることが保証されています。Python寄稿者は、dict
を順序付けすることに切り替えると負のPython> = 3.7でOrderedDict
のパフォーマンスがdict
とどのように比較されるかはわかりませんが、それらは同等であるため、どちらも注文されています。
以下も参照してください。