Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python mmap 모듈 활용법: 메모리 매핑 파일로 빠르게 읽고, 찾고, 쓰기

파이썬 프로그램에서 파일 객체를 읽어 들인 후 내용을 수정하려면 크게 두 가지 방법이 있습니다. 첫 번째는 파일이 실제로 저장된 물리적 드라이브의 내용을 수정하는 방식이고, 두 번째는 시스템의 메모리(RAM)에 있는 데이터를 직접 수정하는 방식입니다. 이 글에서는 파이썬에서 기본 제공되는 mmap 모듈을 사용해 파일 객체를 읽고, 검색하고, 수정하는 방법을 살펴보겠습니다.

일반적으로 파일을 다룰 때는 open, read, lseek 같은 시스템 호출을 반복해서 사용해야 하지만, 메모리 매핑(memory-mapping)은 파일 데이터를 그대로 메모리에 올리기 때문에 마치 메모리상의 객체를 다루듯 파일을 직접 조작할 수 있다는 큰 장점이 있습니다. 특히 대용량 파일을 처리할 때 성능 차이가 두드러집니다.

메모리 매핑된 파일 읽기

아래 예제는 파일 전체를 한 번에 메모리로 읽어 들여 파일 객체 형태로 유지한 뒤, 읽기 모드로 접근하는 방식입니다. 파일 전체가 하나의 객체처럼 동작하므로, 슬라이싱(slicing)으로 원하는 위치의 텍스트를 손쉽게 추출할 수 있습니다.

예제 코드

import mmap

def read_mmap(fname):
    with open(fname, mode="r", encoding="utf8") as fobj:
        with mmap.mmap(fobj.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_obj:
            print(mmap_obj[4:26])

read_mmap('E:\\test.txt')

실행 결과

'emissions from gaseous'

mmap으로 문자열 검색하기

메모리 매핑의 진가는 검색 성능에서 드러납니다. 아래 예제는 일반적인 파일 입출력 방식과 mmap 방식으로 각각 특정 문자열을 찾는 데 걸리는 시간을 비교합니다. 일반 방식은 파일 전체를 먼저 읽어야 하지만, mmap은 이미 메모리에 올라온 데이터를 바로 탐색하므로 실행 시간이 크게 단축됩니다.

예제 코드

import mmap
import time

def regular_io_find(fname):
    with open(fname, mode="r", encoding="utf-8") as fobj:
        text = fobj.read()
        text.find("Death ")

def mmap_io_find(fname):
    with open(fname, mode="r", encoding="utf-8") as fobj:
        with mmap.mmap(fobj.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_obj:
            mmap_obj.find(b"Death ")

start_time_r = time.time()
regular_io_find('E:\\emissions.txt')
end_time_r = time.time()
print("Regular read start time :", start_time_r)
print("Regular read end time :", end_time_r)
print('Regular read time to find : {0}'.format(end_time_r - start_time_r))

start_time_m = time.time()
mmap_io_find('E:\\emissions.txt')
end_time_m = time.time()
print("mmap read start time :", start_time_m)
print("mmap read end time :", end_time_m)
print('mmap read time to find : {0}'.format(end_time_m - start_time_m))

실행 결과

2013
Regular read start time : 1609812463.2718163
Regular read end time : 1609812463.2783241
Regular read time to find: 0.00650787353515625
mmap read start time : 1609812463.2783241
mmap read end time : 1609812463.2783241
mmap read time to find : 0.0

결과를 보면 일반 입출력 방식은 약 0.0065초가 걸린 반면, mmap 방식은 거의 0에 수렴하는 시간 안에 검색을 완료했습니다.

파일에 데이터 쓰기

mmap은 쓰기 작업도 지원합니다. 아래 예제에서는 파일을 r+ 모드(읽기와 쓰기 모두 허용)로 연 뒤, mmap.ACCESS_WRITE 접근 권한으로 메모리 매핑 객체를 생성합니다. 그다음 슬라이싱으로 원하는 위치를 지정하고, 해당 영역에 새 문자열을 덮어쓴 후 flush()를 호출해 변경 사항을 실제 파일에 반영합니다.

예제 코드

import mmap

def mmap_io_write(fname):
    with open(fname, mode="r+") as fobj:
        with mmap.mmap(fobj.fileno(), length=0, access=mmap.ACCESS_WRITE) as mmap_obj:
            mmap_obj[20:26] = b"Hello!"
            mmap_obj.flush()

mmap_io_write('E:\\emissions.txt')

위 코드를 실행한 후 파일을 열어 보면, 20번째 바이트부터 26번째 바이트 위치까지 "Hello!"라는 문자열이 기록된 것을 확인할 수 있습니다.

정리하면, mmap 모듈은 대용량 파일을 반복적으로 읽거나 검색·수정해야 하는 상황에서 시스템 호출 오버헤드를 줄여 주는 강력한 도구입니다. 다만 운영체제마다 동작 세부 사항이 다를 수 있으므로, 실제 프로젝트에 적용하기 전에 사용 환경에서 충분히 테스트해 보는 것이 좋습니다.