2014-04-10 24 views
8

W jaki sposób pamięć RAM jest wymagana do przechowywania danych w pamięci w porównaniu z miejscem na dysku wymaganym do przechowywania tych samych danych w pliku? Czy nie ma uogólnionej korelacji?Rozmiar danych w pamięci a na dysku

Załóżmy na przykład, że mam po prostu miliard wartości zmiennoprzecinkowej. Przechowywany w formie binarnej, czyli 4 miliardy bajtów lub 3,7 GB na dysku (bez nagłówków i innych). Następnie powiedz, że przeczytałem te wartości na liście w Pythonie ... ile pamięci RAM powinienem wymagać?

+0

Więcej pamięci RAM! Między innymi istnieje lista narzutów. Jeśli się martwisz, a) dowiedz się, i b) rozważ jedynie przechowywanie nieprzetworzonych danych w pamięci i rozpakowywanie ich w locie (to zależy od tego, co robisz z tym). – Ryan

+2

Powiązane: http: // stackoverflow.com/a/994010/846892 –

+0

Moja pierwsza myśl jest taka, że ​​upłynie trochę czasu, zanim użytkownik zaczeka, aż wszystkie dane zostaną załadowane do pamięci RAM. –

Odpowiedz

3

Python Object Data Wielkość

Jeśli dane są przechowywane w jakiś obiekt Pythona, będzie trochę więcej danych dołączone do rzeczywistych danych w pamięci.

Można to łatwo sprawdzić.

The size of data in various forms

Warto zwrócić uwagę, jak na początku, narzut obiektu Pythona jest istotna dla małych danych, ale szybko staje się nieistotna.

Oto kod ipython wykorzystywane do generowania działkę

%matplotlib inline 
import random 
import sys 
import array 
import matplotlib.pyplot as plt 

max_doubles = 10000 

raw_size = [] 
array_size = [] 
string_size = [] 
list_size = [] 
set_size = [] 
tuple_size = [] 
size_range = range(max_doubles) 

# test double size 
for n in size_range: 
    double_array = array.array('d', [random.random() for _ in xrange(n)]) 
    double_string = double_array.tostring() 
    double_list = double_array.tolist() 
    double_set = set(double_list) 
    double_tuple = tuple(double_list) 

    raw_size.append(double_array.buffer_info()[1] * double_array.itemsize) 
    array_size.append(sys.getsizeof(double_array)) 
    string_size.append(sys.getsizeof(double_string)) 
    list_size.append(sys.getsizeof(double_list)) 
    set_size.append(sys.getsizeof(double_set)) 
    tuple_size.append(sys.getsizeof(double_tuple)) 

# display 
plt.figure(figsize=(10,8)) 
plt.title('The size of data in various forms', fontsize=20) 
plt.xlabel('Data Size (double, 8 bytes)', fontsize=15) 
plt.ylabel('Memory Size (bytes)', fontsize=15) 
plt.loglog(
    size_range, raw_size, 
    size_range, array_size, 
    size_range, string_size, 
    size_range, list_size, 
    size_range, set_size, 
    size_range, tuple_size 
) 
plt.legend(['Raw (Disk)', 'Array', 'String', 'List', 'Set', 'Tuple'], fontsize=15, loc='best') 
+1

Ta odpowiedź jest nieprawidłowa. Dokumentacja sys.getsizeof stwierdza, że ​​"Uwzględniane jest tylko zużycie pamięci bezpośrednio przypisane do obiektu, a nie zużycie pamięci obiektów, do których się odnosi." Zatem uwzględniono tylko pamięć przydzieloną w kontenerach i nie uwzględniono dodatkowej pamięci przydzielonej dla samych obiektów liczbowych. –

+1

Czy masz zalecenie, jak określić pełną alokację pamięci? Przebuduję fabułę! – tmthydvnprt

+0

Myślę, że musisz dodać 'len (double_list) * sys.getsizeof (1.0)' do raportowanego rozmiaru pamięci dla 'list',' set' i 'tuple'. Prawdopodobnie jest potrzeba dodatkowej pamięci do zarządzania alokacjami, ale nie wiem, jak to zmierzyć i powinno to być pomijalne. –

1

w prostej listy Python, każdy numer podwójnej precyzji wymaga co najmniej 32 bajtów pamięci, ale tylko 8 bajtów są używane do przechowywania rzeczywista liczba, reszta jest niezbędna do wspierania dynamicznej natury Pythona.

Przedmiotem pływak stosowane w CPython jest zdefiniowana w floatobject.h:

typedef struct { 
    PyObject_HEAD 
    double ob_fval; 
} PyFloatObject; 

gdzie PyObject_HEAD jest a macro that expands do PyObject struct:

typedef struct _object { 
    Py_ssize_t ob_refcnt; 
    struct _typeobject *ob_type; 
} PyObject; 

Dlatego każdy obiekt pływający punkt w sklepach Pythona dwa pointer- wielkości pól (każdy zajmuje 8 bajtów w 64-bitowej architekturze) oprócz 8-bajtowego podwójnego, dając 24 bajty pamięci przydzielonej sterty na liczbę. Potwierdza to sys.getsizeof(1.0) == 24.

Oznacza to, że lista n deblu w Pythonie trwa co najmniej 8*n bajtów pamięci tylko do przechowywania wskazówek (PyObject*) do obiektów numerycznych, a każdy obiekt numer wymaga dodatkowych 24 bajtów. By to sprawdzić, spróbuj uruchomić następujące wiersze w Pythonie REPL:

>>> import math 
>>> list_of_doubles = [math.sin(x) for x in range(10*1000*1000)] 

i zobaczyć zużycie pamięci interpretera Pythona (mam około 350 MB pamięci przeznaczonej na moim komputerze x86-64). Zauważ, że jeśli próbowałem:

>>> list_of_doubles = [1.0 for __ in range(10*1000*1000)] 

byś uzyskać zaledwie około 80 MB, ponieważ wszystkie elementy z listy odnoszą się do samym instancji zmiennoprzecinkowej liczby 1.0.

Powiązane problemy