2017-07-21 3 views
5

これは私には完全に困惑しています。PythonのOrderDictとdict()の比較

asset_hist = [] 
for key_host, val_hist_list in am_output.asset_history.items(): 
    for index, hist_item in enumerate(val_hist_list): 
     #row = collections.OrderedDict([("computer_name", key_host), ("id", index), ("hist_item", hist_item)]) 
     row = {"computer_name": key_host, "id": index, "hist_item": hist_item} 
     asset_hist.append(row) 

このコードはコメントアウトコレクションラインと完璧に動作します。しかし、私が行= dict行をコメントアウトし、コレクションの行からコメントを削除すると非常に奇妙になります。これらの行は約400万個生成され、asset_histに追加されます。

したがって、私がrow = dictを使用すると、ループ全体が約10ミリ秒で終了し、雷が速くなります。順序付き辞書を使用すると、10分以上待っていますが、まだ終了していません。さて、私はOrderDictがdictより少し遅いと思われていることを知っていますが、最悪の場合は約10倍遅く、この関数では実際に約10万倍遅くなります。

私は何が起こっていたかを見るために、最も低いループでインデックスを印刷することに決めました。面白いことに、私はコンソール出力でスパッタリングに気づいた。インデックスは画面上で非常に速く印刷され、約3-5秒間停止してから続行します。

am_output.asset_historyは、1つのキーhostを持ち、すべての行が文字列のリストである辞書です。例えば。

am_output.asset_history = {"host1":["string1"、 "string2"、...]、 "host2":["string1"、 "string2"、...]、...}

EDIT:OrderedDict

合計メモリとスパッタ解析このVM Server上:のみ8ギガバイト...続きprovissioned取得する必要があります。

LOOP NUM

184796(約5秒待ち、〜60%のメモリ使用量)

634481(約5秒待ち、〜65%のメモリ使用量)

1197564(〜5秒待機、〜70%のメモリ使用量)

1899247(〜5秒待ち、〜75%メモリ使用量)

2777296(〜5秒待ち、〜80%のメモリ使用量)

3873730(LONG WAITは... 20分を待って!、88.3パーセントのメモリ使用量、プロセスがまだ実行されているあきらめた)待ち時間が各実行で変更をたまたま

を。

EDIT:これをもう一度実行してください。今回は停止する前に停止した場所に3873333で停止します。それは行を形成した後に追加しようとしている間に停止しました...私はこの最後の試みに気づいていませんでしたが、それもそこにありました...問題は行の行ではなく行の行にあります...私はまだですうんざりするここでは、長いストップの直前に作成された行(print文に行を追加したもの)があります。ホスト名は無実を保護するために変更されました:

3873333:OrderedDict([( 'computer_name'、 'bg-fd5612ea' )]))

+1

あなたが観察していることが 'dict'と' OrderedDict'の振る舞いであると信じるのは難しいです。誰かがこれを再現するのに苦労するだろうと思う。 –

+1

ええ、巨大な辞書を最初に生成する必要があります。おそらくランダムな文字列ジェネレータで十分です。しかし、私はまったく真剣です。私は#を1行下に移動するとこれが起こります。順序付き辞書を使用しているときにこのループに詰まっていて、ループを停止するためにCtrl + Cキーを押すと、何も起こりません。Ctrl + Zキーを押す必要があります。 – gunslingor

+0

どのPythonのバージョンですか?最新のOrderedDictは単にdictのエイリアスです。現在の実装は実装の詳細によって順序付けされているためです。 – RemcoGerlich

答えて

1

あなた自身のテストが証明しているように、ドメイン名は、あなたは記憶が不足しています。 CPython 3でも(実際にはdictが注文されていますが、言語保証はしていませんが)OrderedDictは、dictと比較してメモリオーバーヘッドが大きくなります。 move_to_endなどで並べ替えることができます。sys.getsizeofで確認できます(正確な結果はPythonのバージョンとビルドのビット幅によって異なります)。32ビット対64ビット):

格納されたデータを無視
>>> od = OrderedDict([("a", 1), ("b", 2), ("c", 3)]) 
>>> d = {**od} 
>>> sys.getsizeof(od) 
464 # On 3.5 x64 it's 512 
>>> sys.getsizeof(d) 
240 # On 3.5 x64 it's 288 

、ここOrderedDictのオーバーヘッドは、ほぼその倍の平野dictのです。これらのアイテムを4百万個作っているのであれば、私のマシン上で、850 MB以上の溝のオーバーヘッドが(3.5と3.6の両方で)加算されます。

システム上の他のすべてのプログラムとPythonプログラムの組み合わせが、マシンに割り当てられているRAMを超えている可能性があります。スワップスラッシングが滞っています。特に、asset_histが新しいエントリのために拡張する必要があるときはいつも、(使用不足のためにページアウトされた)大きな部分をページする必要があり、周期的なガベージコレクションの実行がトリガするときはいつでも(フルGCは、デフォルトでは割り当て解除)、すべてのOrderedDictがページを取得してサイクル外で参照されているかどうかを確認します(サイクリックGC via gc.disable()を無効にしてGC実行が主な問題かどうかを確認できます)。

具体的な使用例がある場合は、dictOrderedDictの両方を避けることを強くおすすめします。オーバーヘッドがdictであっても、Python 3.6のほうが安いフォームであっても、まったく3つの固定キーが繰り返し設定されていると極端です。代わりに、use collections.namedtupleは、名前またはインデックス(標準のtupleのように動作しますが、名前付き属性として各値にアクセスすることもできます)を参照できる軽量オブジェクト用に設計されているため、プログラムのメモリコストを大幅に削減しますメモリが問題ではない時でさえ)。例えば

from collections import namedtuple 

ComputerInfo = namedtuple('ComputerInfo', ['computer_name', 'id', 'hist_item']) 

asset_hist = [] 
for key_host, val_hist_list in am_output.asset_history.items(): 
    for index, hist_item in enumerate(val_hist_list): 
     asset_hist.append(ComputerInfo(key_host, index, hist_item)) 

使用中の唯一の違いは、あなたがrow.computer_namerow['computer_name']を交換するか、すべての値が必要な場合は、例えば、通常のtupleのようにそれを解凍することができるということですcomphost, idx, hist = row。本当にOrderedDictが必要な場合(すべてを保存しないでください)row._asdict()と入力してnamedtupleと同じマッピングでOrderedDictを取得できますが、通常は必要ありません。メモリ節約は意味があります。私のシステムでは、3つの要素namedtupleは、項目当たりのオーバーヘッドを72バイトに落とし、3.6/dictの三分の一も少なく、3.6 の1/6未満です(3つの要素namedtupleは3.5の72バイトのままです./OrderedDictは3.6より大きい)。それはそれ以上に節約するかもしれません。 tuple(およびnamedtuple)は、連続した1つのC structとして割り当てられますが、dictおよびcompanyは少なくとも2つの割り当てです(オブジェクト構造の場合は1つ、構造の動的にサイズ変更可能な部分の場合は1つ以上)。アロケータオーバーヘッドとアライメントコストを支払う。

どちらの方法でも、namedtupleを使用して400万行のシナリオを実行すると、合計で約275MBのオーバーヘッドを支払うことになります(dictと1770では915(3.6)〜1100(3.5)MB) (3.6)-19550(3.5)OrderedDictのMB。あなたが8 GBのシステムについて話しているときに、あなたのオーバーヘッドから1.5 GBを削ることが大きな改善です。

関連する問題