Get in touch
or send us a question?
CONTACT

Interger và list trong Python và tiết kiệm memory với Numpy

Giả sử muốn tạo 1 List integer:

array = list(range(1000000))

Bạn đoán Python sẽ dùng bao nhiêu memory để lưu “đồng chí” array kia? Hmm… Ở đại học ta được học integer là 4 bytes, vậy tính ra với một triệu phần tử thì sẽ ~4MiB?

Trong thực tế, Python tốn ~36MiB để lưu array và các số integer này. Sử dụng memory_profiler để profile memory usage của code.

Line #    Mem usage    Increment   Line Contents
================================================
     1   37.586 MiB   37.586 MiB   @profile
     2                             def test_list():
     3   74.184 MiB   36.598 MiB       array = list(range(1000000))

Tại sao?

Trong Python, mọi thứ đều là object vì thế mà sẽ tốn thêm 1 lượng bytes cho overhead memory.

In [1]: number = 1; number.__dir__()
Out[1]: 
['__repr__',
 '__hash__',
 '__getattribute__',
 '__lt__',
 '__le__',
 '__eq__',
 '__ne__',
 '__gt__',
...]
In [2]: number.__sizeof__()
Out[2]: 28

Oh, 28 bytes. Quay về với ví dụ ban đầu, sẽ là ~28MiB cho 1 triệu số integer. Vậy còn ~8MiB nữa đi đâu? ~8MiB đó thuộc về object ARRAY. List trong python là 1 mảng các pointer (con trỏ) trỏ tới bất kỳ object nào. Với ví dụ của chúng ta sẽ là 1 triệu pointers. Trong hệ điều hành 64-bit, con trỏ chiếm 8 bytes.

In [3]: arr.__sizeof__()
Out[3]: 8000040

NUMPY thì sao?

Khác với kiểu list, numpy array không lưu reference tới bất kỳ Python object nào mà thay vào đó chỉ lưu các số mà thôi.

import numpy as np
arr = np.zeros((1000000,), dtype=np.uint32)
for i in range(1000000):
    arr[i] = i

ta được kết quả như sau:

Line #    Mem usage    Increment   Line Contents
================================================
     8   37.711 MiB   37.711 MiB   @profile
     9                             def test_numpy():
    10   50.414 MiB   12.703 MiB       import numpy as np
    11                             
    12   50.414 MiB    0.000 MiB       arr = np.zeros((1000000,), dtype=np.uint32)
    13   54.586 MiB    0.000 MiB       for i in range(1000000):
    14   54.586 MiB    0.562 MiB           arr[i] = i

Vậy là chỉ tốn 4MiB cho array, giống như đã được dạy ở trên đại học

Kết luận

Sự chênh lệch giữa 4MiB và 36MiB có thể là không lớn và ta có thể sống vui vẻ, nhưng giữa 4GiB và 36GiB lại là một chuyện rất lớn.