엄청 큰 숫자 시퀀스 자료가 있는 경우 이를 생성하고 저장, 및 로딩하는 과정에서 array 를 활용하면 매우 빠르게 처리할 수 있다.
from random import random
from array import array
from time import perf_counter as pc
create_time = pc()
test_float = array("d", [random() for _ in range(10 ** 7)])
print("생성 소요시간 :", pc() - create_time)
save_time = pc()
with open("abcd_test.bin", "wb") as file:
test_float.tofile(file)
print("저장 소요시간 :", pc() - save_time)
load_time = pc()
test_float2 = array("d")
with open("abcd_test.bin", "rb") as file:
test_float2.fromfile(file, 10 ** 7)
print("로딩 소요시간 :", pc() - load_time)
print(test_float2 == test_float)
생성 소요시간 : 1.217794247
저장 소요시간 : 0.04572359199999987
로딩 소요시간 : 0.08720557899999992
True
array 의 tofile/fromfile method 를 통해서 쉽게 숫자가 매우 많은 시퀀스 자료형을 저장하고 불러올 수 있다. 천 만건의 실수형 데이터를 불러오는 데에 0.8초 밖에 소요되지 않았다.
반복문으로 line by line 으로 불러오는 데에 14초 정도 걸렸으니 매우 큰 효율 차이를 보인다는 것을 알 수 있다.
더불어서 memoryview 를 사용하면, 보다 적은 메모리를 사용하면서도 원본 데이터를 수정할 수 있다.
mv = memoryview(test_float2)
print("test_float size : ", sys.getsizeof(test_float))
print("test_float2 size : ", sys.getsizeof(test_float2))
print("memoryview size : ", sys.getsizeof(mv))
print("memoryview length : ", len(mv))
print("test_float2(slicing) size : ", sys.getsizeof(test_float2[1000000:]))
print("memoryview(slicing) size : ", sys.getsizeof(mv[1000000:]))
> test_float size : 80000064
> test_float2 size : 85000088
> memoryview size : 200
> memoryview length : 10000000
> test_float2(slicing) size : 72000064
> memoryview(slicing) size : 200
memoryview 의 원본과 동일하게 천 만건의 데이터를 가지고 있음에도 200bytes 밖에 차지하지 않는다. 원본이 85000088bytes 인 점을 감안하면 큰 차이다.
일반적으로 시퀀스 자료형은 PyObject 포인터이다. 즉, 객체 자체를 포함하는 게 아닌 객체의 위치를 가리키는 레퍼런스를 가진다.
memoryview 는 C level structure인 버퍼를 활용하여 bytes 와 bytearray 같이 버퍼 프로토콜을 지원하는 내장 객체에 대하여 원본을 복사하지 않고 메모리를 공유한다.
'python' 카테고리의 다른 글
Architecture Patterns with Python(1장) (0) | 2021.10.09 |
---|---|
Fluent Python (챕터 2) (0) | 2021.10.07 |
Fluent Python (챕터1) (0) | 2021.10.06 |
ChainMap (0) | 2021.05.07 |
슬라이스와 범위 지정 시에 마지막 항목이 포함되지 않는 이유 (0) | 2021.05.02 |