web-dev-qa-db-ja.com

メモリ効率:1つの大きな辞書または小さな辞書の辞書?

Python(2.6)で、辞書をデータストアとして使用する必要があるアプリケーションを作成しています。

1つの大きな辞書を使用する方がメモリ効率が高いかどうか、またはそれを多くの(はるかに)小さな辞書に分割してから、すべての小さな辞書への参照を含む「インデックス」辞書を作成する方がメモリ効率が高いかどうかについて知りたいです。

リストや辞書には、一般的に多くのオーバーヘッドがあることを私は知っています。 pythonは、辞書/アイテムのリスト数が2の累乗になるのに十分なスペースを内部的に割り当てることをどこかで読みました。

私はpythonのように十分に新しいので、そのような他の予期しない内部の複雑さ/驚きがあるかどうかはわかりません。それは私が考慮に入れるべき平均的なユーザーには明らかではありません。

難しさの1つは、2つのシステムの力が「アイテム」をどのようにカウントするかを知ることです。各key:pairは1つのアイテムとしてカウントされますか? 100アイテムのモノリシック辞書がある場合、スペース100 ^ 2アイテムが割り当てられるため、これを知っておくことが重要です。 100個の単一アイテム辞書(1キー:ペア)がある場合、各辞書は割り当て1 ^ 2のみになります(別名、追加の割り当てはありません)?

明確にレイアウトされた情報は非常に役立ちます!

34
Brandon K

3つの提案:

  1. 1つの辞書を使用します。
    それはより簡単で、より簡単であり、他の誰かがすでにこの問題をあなたのために最適化しています。実際にコードを測定し、パフォーマンスの問題をコードのこの部分まで追跡するまでは、単純で単純なことを行わない理由はありません。

  2. 後で最適化してください。
    パフォーマンスが本当に心配している場合は、問題を抽象化して、最終的に使用するルックアップメカニズムをラップするクラスを作成し、このクラスを使用するコードを記述します。パフォーマンスを向上させるために他のデータ構造が必要な場合は、後で実装を変更できます。

  3. ハッシュテーブルを読んでください。
    辞書は ハッシュテーブル であり、時間やスペースのオーバーヘッドが心配な場合は、それらがどのように実装されているかを確認する必要があります。これは基本的なコンピュータサイエンスです。要するに、ハッシュテーブルは次のとおりです。

    • 平均的なケースO(1)ルックアップ時間
    • O(n)スペース(さまざまなパラメーターに応じて、2nについて期待します)

    それらがO(n ^ 2)スペースであるとあなたがどこで読んだかはわかりませんが、もしそうなら、それらは広く実用的ではないでしょう今日のほとんどの言語でそのまま使用します。ハッシュテーブルのこれらのNiceプロパティには、次の2つの利点があります。

    1. O(1)ルックアップ時間は、ルックアップ時間がサイズに依存しないため、より大きな辞書を持つためにルックアップ時間のコストを支払わないことを意味します。
    2. O(n)スペースは、辞書を細かく分割しても何も得られないことを意味します。スペースは要素の数に比例して変化するため、多くの小さな辞書が1つの大きな辞書よりも大幅に少ないスペースを占めることはありません。その逆も同様です。 O(n ^ 2)スペースの場合、これは当てはまりませんが、幸運なことに、そうではありません。

    役立つ可能性のあるその他のリソースは次のとおりです。

    • ハッシュテーブルに関するウィキペディアの記事 は、ハッシュテーブルで使用されるさまざまなルックアップおよび割り当てスキームの優れたリストを提供します。
    • GNUスキームのドキュメント は、ハッシュテーブルが占めると予想されるスペースの量についての素晴らしい議論を持っています。これには、なぜ "ハッシュテーブルによって使用されるスペースの量の正式な議論も含まれます。テーブル内の関連付けの数に比例します」。これはあなたに興味があるかもしれません。

    辞書の実装を実際に最適化する必要があると思われる場合は、次のことを検討してください。

    • すべての詳細が必要な場合に備えて、Pythonの辞書のCソースコードを次に示します。ここには豊富なドキュメントがあります:
    • Cを読みたくない場合に備えて、これが python実装 です。
      (ありがとう Ben Peterson
    • Java Hashtable class docs 負荷係数がどのように機能するか、および負荷係数がハッシュが占めるスペースにどのように影響するかについて少し話します。負荷率と再ハッシュする必要がある頻度の間にはトレードオフがあることに注意してください。再ハッシュにはコストがかかる場合があります。
75
Todd Gamblin

Pythonを使用している場合は、そもそもこの種のことを心配する必要はありません。コンピュータではなく、yourのニーズに最適な方法でデータ構造を構築するだけです。

これは、パフォーマンスの向上ではなく、時期尚早の最適化のスマックです。何かが実際にボトルネックになっている場合はコードのプロファイルを作成しますが、それまでは、Pythonに実行させて、基礎となるメカニズムではなく、実際のプログラミングタスクに焦点を合わせてください。

16
Soviut

特に「シンプル」を超える理由がテストされていない場合は、「シンプル」の方が「賢い」よりも一般的に優れています。とにかく、「メモリ効率」はあいまいな用語であり、永続化、シリアル化、キャッシュ、スワッピング、および他の誰かがすでに考えている他の多くのものを検討するとき、トレードオフがあります。ほとんどの場合、あなたはそうしません。する必要があります。

「それを適切に処理する最も簡単な方法」は、ずっと後で最適化することを考えてください。

8
dkretz

時期尚早の最適化何とか何とか、それを何とかしないでください。

私はあなたが2つの余分な割り当てのについて間違っていると思います。私はそれがちょうど2の乗数 2だと思います。 x ^ 2ではなくx * 2。

私はこの質問をさまざまなpythonメーリングリストで数回見ました。

メモリに関して、これはそのような議論の1つの言い換えバージョンです(問題の投稿は数億の整数を格納したかった):

  1. メンバーシップをテストしたいだけの場合、set()はdict()よりもスペース効率が高い
  2. gmpyには、密な整数のセットを格納するためのビットベクトル型クラスがあります。
  3. ディクトは50%から30%の間で空に保たれ、エントリは約12バイトです(ただし、実際の量はプラットフォームによって少し異なります)。

したがって、オブジェクトが少ないほど、使用するメモリも少なくなり、実行するルックアップも少なくなります(インデックスでルックアップしてから、実際の値で2回目のルックアップを行う必要があるため) 。

他の人と同じように、プロファイルを作成してボトルネックを確認します。メンバーシップset()と値dict()を維持する方が速いかもしれませんが、より多くのメモリを使用することになります。

また、これをpython comp.lang.pythonなどの特定のリストに再投稿することをお勧めします。このリストには、私よりもはるかに知識が豊富で、あらゆる種類の有用な情報が提供されます。

7

辞書が大きすぎてメモリに収まらない場合は、Python用の非常に成熟したオブジェクトデータベースである [〜#〜] zodb [〜#〜] を確認することをお勧めします。

データベースの「ルート」は辞書と同じインターフェースを持っており、データ構造全体を一度にメモリにロードする必要はありません。開始キーと終了キーを指定することで、構造の一部のみを反復処理できます。

また、トランザクションとバージョン管理も提供します。

5
EoghanM

正直なところ、パフォーマンスまたはメモリ使用量のいずれの点でも、どちらの方法でも違いを区別することはできません。数千万以上のアイテムを扱っているのでない限り、パフォーマンスやメモリへの影響は単なるノイズです。

2番目の文の言い方からすると、1つの大きな辞書が最初の傾向であり、解決しようとしている問題とより密接に一致しているように見えます。それが本当なら、それで行きなさい。 Pythonについてわかることは、誰もが「正しい」と考えるソリューションは、ほとんどの場合、可能な限り明確で単純なソリューションであることが判明するということです。

2
DNS

多くの場合、辞書の辞書はパフォーマンス上の理由以外に役立ちます。つまり、オブジェクト自体に追加のフィールドを持たずにデータに関するコンテキスト情報を格納し、データのサブセットのクエリを高速化できます。

メモリ使用量の観点から、1つの大きな辞書が複数の小さな辞書よりも少ないRAMを使用するのは当然のことです。辞書をネストしている場合は、ネストのレイヤーを追加するたびに、割り当てる必要のある辞書の数が約2倍になることを忘れないでください。

クエリ速度に関しては、必要なルックアップの数が増えるため、複数のdictの方が時間がかかります。

したがって、この質問に答える唯一の方法は、独自のコードをプロファイリングすることだと思います。ただし、私の提案は、コードを最もクリーンで保守しやすい方法を使用することです。 Pythonのすべての機能の中で、辞書はおそらく最適なパフォーマンスのために最も大幅に調整されています。

1
Daniel Naab