10

私が少しテストしたように、3,000 万項目の int=>int (異なる値) の python dict は、私の Mac で 2G を超えるメモリを簡単に消費する可能性があります。私は int to int dict のみを使用しているため、python dict を使用するよりも良い解決策はありますか?

私が必要とするいくつかの要件は、

  1. 数千万レベルの int から int アイテムを保持する際のメモリ効率が向上
  2. キーによる値のフェッチやすべてのアイテムの反復などの基本的な dict メソッド
  3. 文字列/バイナリに簡単にシリアル化できるとプラスになります

更新、4. d.fromkeys([...]) のように、特定のキーでサブセットを簡単に取得できます

ありがとう。

4

4 に答える 4

9

少なくとも 2 つの可能性があります。

配列

2 つの配列を使用してみることができます。1 つはキー用、もう 1 つは値用であるため、index(key) == index(value)

2017 年 1 月 5 日更新:配列で 4 バイト整数を使用します。

配列はより少ないメモリを使用します。python が clang でコンパイルされた 64 ビット FreeBSD マシンでは、3000 万の整数の配列は約 117 MiB を使用します。

これらは私が使用したpythonコマンドです:

Python 2.7.13 (default, Dec 28 2016, 20:51:25) 
[GCC 4.2.1 Compatible FreeBSD Clang 3.8.0 (tags/RELEASE_380/final 262564)] on freebsd11
Type "help", "copyright", "credits" or "license" for more information.
>>> from array import array
>>> a = array('i', xrange(30000000))
>>> a.itemsize
4

アレイのインポート後、次のようにps報告されます。

USER     PID %CPU %MEM   VSZ  RSS TT  STAT STARTED    TIME COMMAND
 rsmith 81023  0.0  0.2  35480   8100  0  I+   20:35     0:00.03 python (python2.7)

配列を作成した後:

USER     PID %CPU %MEM    VSZ    RSS TT  STAT STARTED    TIME COMMAND
rsmith 81023 29.0  3.1 168600 128776  0  S+   20:35     0:04.52 python (python2.7)

Resident Set Size は 1 KiB 単位で報告されるため、(128776 - 8100)/1024 = 117 MiB

リスト内包表記を使用すると、キーが特定の条件を満たすインデックスのリストを簡単に取得できます。次に、そのリストのインデックスを使用して、対応する値にアクセスできます...

でこぼこ

numpy が利用できる場合は、それを使用する方が高速で、より多くの機能があり、使用する RAM がわずかに少なくなります。

Python 2.7.5 (default, Jun 10 2013, 19:54:11) 
[GCC 4.2.1 Compatible FreeBSD Clang 3.1 ((branches/release_31 156863))] on freebsd9
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> a = np.arange(0, 30000000, dtype=np.int32)

From ps: Python 起動後 6700 KiB、numpy インポート後 17400 KiB、配列作成後 134824 KiB。これは約 114 MiB です。

さらに、numpy はレコード配列をサポートしています。

Python 2.7.5 (default, Jun 10 2013, 19:54:11) 
[GCC 4.2.1 Compatible FreeBSD Clang 3.1 ((branches/release_31 156863))] on freebsd9
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> a = np.zeros((10,), dtype=('i4,i4'))
>>> a
array([(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0),
       (0, 0), (0, 0)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])
>>> a.dtype.names
('f0', 'f1')
>>> a.dtype.names = ('key', 'value')
>>> a
array([(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0),
       (0, 0), (0, 0)], 
      dtype=[('key', '<i4'), ('value', '<i4')])
>>> a[3] = (12, 5429)
>>> a
array([(0, 0), (0, 0), (0, 0), (12, 5429), (0, 0), (0, 0), (0, 0), (0, 0),
       (0, 0), (0, 0)], 
      dtype=[('key', '<i4'), ('value', '<i4')])
>>> a[3]['key']
12

ここでは、キーと値に個別にアクセスできます。

>>> a['key']
array([ 0,  0,  0, 12,  0,  0,  0,  0,  0,  0], dtype=int32)
于 2013-08-04T10:44:14.743 に答える
2

使いやすい辞書のようなカウンターが必要な場合は、別の回答が追加されました。

Python 標準ライブラリの高性能 Counter オブジェクト

于 2013-08-15T08:13:56.433 に答える
1

それがどのように使用されるかについてもう少し知っていれば、良い解決策を提案するのがより簡単になるかもしれません. キーで値をフェッチし、それらすべてを反復処理したいと言いますが、データを挿入/削除する必要があるかどうかについては何もありません。

データを格納する非常に効率的な方法の 1 つは、arrayモジュールを使用することです。データを挿入/削除する必要がない場合は、単純に 2 つの配列を使用できます。「キー」配列はソートされ、正しいキーのバイナリ検索を実行できます。次に、他の配列の同じ位置から値を選択するだけです。

dict のように動作するクラスにそれを簡単にカプセル化できます。どこかにこれに対する解決策があるかどうかはわかりませんが、実装するのはそれほど難しいことではありません。これは、メモリを消費する多くの python オブジェクトを避けるのに役立ちます。

ただし、そのようなソリューションを非現実的/不可能にする他の要件がある場合があります。

于 2013-08-04T10:43:50.367 に答える