timeit 라이브러리는 작은단위의 코드에 실행시간을 테스트할 수 있는 유용한 도구입니다.
이 도구를 사용하여 파이썬에서 제공해주는 단순한 바이트배열과 memoryview 라는 객체를 활용하였을 때
성능적으로 얼마나 큰 차이점이 발생하고 왜 이런 차이점이 발생하는지 알아보겠습니다
import os
import timeit
video_data = 100 * os.urandom(1024 * 1024)
byte_offset = 1234
size = 20 * 1024 * 1024
def run_test():
chunk = video_data[byte_offset:byte_offset + size]
result = timeit.timeit(
stmt='run_test()',
globals=globals(),
number=100) / 100
print(f'{result:0.9f} seconds')
# 0.001633870 seconds
video_view = memoryview(video_data)
def run_test2():
chunk = video_view[byte_offset:byte_offset + size]
result = timeit.timeit(
stmt='run_test2()',
globals=globals(),
number=100) / 100
print(f'{result:0.9f} seconds')
# 0.000000150 seconds
기존 바이트배열을 활용하면 1633870(소수점생략) 이 걸리던 것이 똑같은 데이터를 memoryview로 감싸서
실행한 결과, 150 밖에 걸리지 않습니다.
초로 환산하면 1.6초(대략), 0.00015초 차이가 납니다.
여기서 만일 바이트배열을 활용해 1분이 걸리는 작업이 있다고 가정한다면,
memoryview에서는 0.0xx 초 단위로 실행이 되니 실로 어마어마한 차이며,
만일 동영상데이터를 서비스하기 위해 1초동안 10MB 데이터들을 처리해야 한다면
0.001633870/1 * 10MB = 600MB (대략)
0.000000150/1 * 10MB ≈ 66,666MB/초 ≈ 65GB/초
를 처리할 수 있을 것이고 결과를 보고 속도차이에 대한 체감이 될 것 같습니다
그렇다면 도대체 memoryview는 어떤 녀석이길래 이런 미친성능을 보여주는 것일까요?
memoryview는 파이썬에서 제공하는 고성능 버퍼 프로토콜을 활용한 내장 타입입니다.
이를 사용하면 객체의 슬라이스에 대해 복사 없이 직접 읽고 쓸 수 있는 인터페이스를 얻을 수 있습니다.
이는 바이트 슬라이싱을 할 때 메모리를 복사하여 CPU 시간을 점유하는 방식에 비해 뛰어난 성능을 보여주고 있음을 위에서 알 수 있죠.
버퍼 프로토콜
버퍼 프로토콜은 객체가 아닌, 하부 데이터 버퍼에 접근할 수 있는 저수준의 C API입니다.
이를 통해 개발자는 객체의 메모리 레이아웃에 직접 접근할 수 있게 되어, 데이터 처리의 효율성이 크게 향상됩니다.
memoryview의 장점
memoryview의 주요 장점 중 하나는 슬라이싱을 할 때 새로운 memoryview 인스턴스를 생성한다는 것입니다.
이는 메모리 복사가 발생하지 않고, 대용량 데이터를 처리할 때 시간과 메모리 사용량을 크게 절약할 수 있습니다.
bytearray와의 조합
bytearray는 bytes와 유사하지만 변경 가능한 타입을 제공합니다.
memoryview를 bytearray로 감싸면, 복사의 추가 비용 없이 수신받은 데이터를 버퍼에서 원하는 위치에 스플라이스할 수 있게 됩니다. 그래서 네트워크 통신이나 파일 입출력 등에서 데이터를 효율적으로 처리할 수 있게 해줍니다.
결론
memoryview는 파이썬의 버퍼 프로토콜을 활용하여, 데이터를 복사하지 않고도 직접 읽고 쓸 수 있는 인터페이스를 제공합니다.
이를 통해 개발자는 메모리 사용과 CPU 시간을 크게 절약할 수 있으며, 특히 대용량 데이터를 다룰 때 이러한 이점이 두드러집니다. bytearray와 결합하여 사용하면, 데이터의 효율적인 처리가 가능해져 고성능 애플리케이션 개발에 성능을 최적화하는데 꼭 필요한 기능이라고 생각됩니다
memoryview와 bytearray와의 차이점을 설명한 그림

'프로그래밍 언어 > Python' 카테고리의 다른 글
| asyncio를 활용해 간단하게 서버 구현한 코드 리뷰하기 (0) | 2023.09.22 |
|---|---|
| 소켓코드를 보고 현상정리 ( feat. 버퍼 ) (1) | 2023.09.21 |
| with와 @contextlib.contextmanager (0) | 2023.09.20 |
| 컨텍스트 스위칭으로부터의 예상치 못한 결과 ( feat.GIL ) (0) | 2023.09.20 |
| Thread와 Queue를 활용한 파이프라인 구현하기( feat. 콘웨이 생명게임 ) (0) | 2023.09.19 |