redditmetrics.com によると、Redditには100万を超えるサブレディットがあります。
すべてのsubredditが配列に格納されるまで このReddit APIエンドポイント を繰り返しクエリするスクリプトを作成しました。all_subs
:
all_subs = []
for sub in <repeated request here>:
all_subs.append({"name": display_name, "subscribers": subscriber_count})
スクリプトは10時間近く実行されており、ほぼ半分完了しています(3〜4回のリクエストごとにレート制限されます)。終了したら、次のような配列を期待します。
[
{ "name": "AskReddit", "subscribers", 16751677 },
{ "name": "news", "subscribers", 13860169 },
{ "name": "politics", "subscribers", 3350326 },
... # plus one million more entries
]
このリストはメモリ内でおよそどのくらいのスペースを占有しますか?
これはあなたのPythonバージョンとあなたのシステムに依存しますが、それがどれだけのメモリを必要とするかを理解するためにあなたに手を差し伸べます。最初に最初に、 _sys.getsizeof
_ は、コンテナを表すobjectのメモリ使用量のみを返し、コンテナ内のすべての要素は返しません。
オブジェクトに直接起因するメモリ消費のみが考慮され、参照するオブジェクトのメモリ消費は考慮されません。
指定した場合、オブジェクトがサイズを取得する手段を提供しない場合、デフォルトが返されます。そうしないと、TypeErrorが発生します。
getsizeof()
は、オブジェクトの___sizeof__
_メソッドを呼び出し、オブジェクトがガベージコレクターによって管理されている場合は、ガベージコレクターのオーバーヘッドを追加します。
getsizeof()
を再帰的に使用してコンテナーのサイズとそのすべての内容を見つける例については、 recursive sizeofレシピ を参照してください。
だから、私はそのレシピをインタラクティブなインタプリタセッションにロードしました:
したがって、CPythonlistは、実際には異種のサイズ変更可能な配列リストです。基になる配列には、Py_Objectsへのポインターのみが含まれます。したがって、ポインタはマシンのワード相当のメモリを占有します。 64ビットシステムでは、これは64ビットなので、8バイトです。したがって、コンテナの場合、サイズ1,000,000のリストは約800万バイト、つまり8メガバイトを占めます。 1000000エントリのリストを作成すると、次のことがわかります。
_In [6]: for i in range(1000000):
...: x.append([])
...:
In [7]: import sys
In [8]: sys.getsizeof(x)
Out[8]: 8697464
_
余分なメモリは、pythonオブジェクトのオーバーヘッドと、効率的な_.append
_操作を可能にするために基になる配列が最後に残す余分なスペースによって占められます。
現在、Pythonでは辞書はかなり重いです。コンテナだけ:
_In [10]: sys.getsizeof({})
Out[10]: 288
_
したがって、100万ディクトのサイズの下限は288000000バイトです。したがって、大まかな下限:
_In [12]: 1000000*288 + 1000000*8
Out[12]: 296000000
In [13]: 296000000 * 1e-9 # gigabytes
Out[13]: 0.29600000000000004
_
したがって、約0.3ギガバイト相当のメモリが期待できます。レシピとより現実的なdict
の使用:
_In [16]: x = []
...: for i in range(1000000):
...: x.append(dict(name="my name is what", subscribers=23456644))
...:
In [17]: total_size(x)
Out[17]: 296697669
In [18]:
_
だから、約0.3ギグ。さて、それは現代のシステムではそれほど多くありません。ただし、スペースを節約したい場合は、Tuple
またはそれ以上のnamedtuple
を使用する必要があります。
_In [24]: from collections import namedtuple
In [25]: Record = namedtuple('Record', "name subscribers")
In [26]: x = []
...: for i in range(1000000):
...: x.append(Record(name="my name is what", subscribers=23456644))
...:
In [27]: total_size(x)
Out[27]: 72697556
_
または、ギガバイト単位:
_In [29]: total_size(x)*1e-9
Out[29]: 0.07269755600000001
_
namedtuple
はTuple
と同じように機能しますが、namesでフィールドにアクセスできます。
_In [30]: r = x[0]
In [31]: r.name
Out[31]: 'my name is what'
In [32]: r.subscribers
Out[32]: 23456644
_