メモリ使用量と CPU 消費の観点から、Python では辞書とオブジェクトのどちらがより効率的でしょうか?
背景:膨大な量のデータを Python にロードする必要があります。フィールド コンテナーだけのオブジェクトを作成しました。400 万個のインスタンスを作成し、それらを辞書に格納するのに約 10 分かかり、メモリは約 6 GB 消費されました。辞書の準備ができたら、それにアクセスするのは一瞬です。
例:パフォーマンスを確認するために、同じことを実行する 2 つの簡単なプログラムを作成しました。1 つはオブジェクトを使用し、もう 1 つは辞書を使用しています。
オブジェクト(実行時間約18秒):
class Obj(object):
def __init__(self, i):
self.i = i
self.l = []
all = {}
for i in range(1000000):
all[i] = Obj(i)
辞書(実行時間約12秒):
all = {}
for i in range(1000000):
o = {}
o['i'] = i
o['l'] = []
all[i] = o
質問:私が何か間違っているのでしょうか、それとも辞書の方がオブジェクトよりも速いだけでしょうか? 実際に辞書のパフォーマンスが優れているのであれば、その理由を誰か説明してもらえますか?
ベストアンサー1
使ってみましたか__slots__
?
からドキュメンテーション:
デフォルトでは、古いスタイルと新しいスタイルの両方のクラスのインスタンスには、属性を格納するための辞書があります。これにより、インスタンス変数が非常に少ないオブジェクトのスペースが無駄になります。大量のインスタンスを作成すると、スペースの消費が深刻になる可能性があります。
デフォルトは、
__slots__
新しいスタイルのクラス定義で定義することでオーバーライドできます。宣言はインスタンス変数のシーケンスを受け取り、各インスタンスに各変数の値を保持するのに十分なスペースを予約します。インスタンスごとには作成されない__slots__
ため、スペースが節約されます。__dict__
それで、メモリだけでなく時間も節約できるのでしょうか?
私のコンピューターで 3 つのアプローチを比較します。
test_slots.py:
class Obj(object):
__slots__ = ('i', 'l')
def __init__(self, i):
self.i = i
self.l = []
all = {}
for i in range(1000000):
all[i] = Obj(i)
テストオブジェクト:
class Obj(object):
def __init__(self, i):
self.i = i
self.l = []
all = {}
for i in range(1000000):
all[i] = Obj(i)
テスト辞書:
all = {}
for i in range(1000000):
o = {}
o['i'] = i
o['l'] = []
all[i] = o
test_namedtuple.py (2.6 でサポート):
import collections
Obj = collections.namedtuple('Obj', 'i l')
all = {}
for i in range(1000000):
all[i] = Obj(i, [])
ベンチマークを実行します(CPython 2.5 を使用):
$ lshw | grep product | head -n 1
product: Intel(R) Pentium(R) M processor 1.60GHz
$ python --version
Python 2.5
$ time python test_obj.py && time python test_dict.py && time python test_slots.py
real 0m27.398s (using 'normal' object)
real 0m16.747s (using __dict__)
real 0m11.777s (using __slots__)
名前付きタプルテストを含む CPython 2.6.2 を使用します。
$ python --version
Python 2.6.2
$ time python test_obj.py && time python test_dict.py && time python test_slots.py && time python test_namedtuple.py
real 0m27.197s (using 'normal' object)
real 0m17.657s (using __dict__)
real 0m12.249s (using __slots__)
real 0m12.262s (using namedtuple)
はい、(驚くことではありませんが) を使用すると__slots__
パフォーマンスが最適化されます。名前付きタプルを使用すると、 と同様のパフォーマンスが得られます__slots__
。