python

array 로 생성, 저장, 로딩

monsterkos 2021. 5. 2. 19:48

엄청 큰 숫자 시퀀스 자료가 있는 경우 이를 생성하고 저장, 및 로딩하는 과정에서 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 같이 버퍼 프로토콜을 지원하는 내장 객체에 대하여 원본을 복사하지 않고 메모리를 공유한다.