Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

Cách cải thiện hiệu năng đọc file trong Python với hàm MMAP

Giới thiệu

MMAP (Memory Mapping - ánh xạ bộ nhớ) khi ánh xạ tới file sử dụng bộ nhớ ảo của hệ điều hành để truy cập dữ liệu trên hệ thống file trực tiếp, thay vì dùng các hàm I/O thông thường. Do đó cải thiện hiệu năng I/O vì không cần gọi hệ thống riêng cho mỗi truy cập hoặc sao chép dữ liệu giữa các bộ đệm.

Thực tế, bất kỳ dữ liệu nào trong bộ nhớ (ví dụ: database SQLite tạo trong bộ nhớ) đều có hiệu năng tốt hơn so với trên đĩa.

File ánh xạ bộ nhớ có thể được xử lý như chuỗi có thể thay đổi (mutable strings) hoặc đối tượng giống file (file-like objects), tùy mục đích.

MMAP hỗ trợ nhiều phương thức: close(), flush(), read(), readline(), seek(), tell(), write() và hoạt động tốt với thao tác cắt lát (slice) và biểu thức chính quy.

Cách thực hiện

1. Tạo file văn bản mẫu

Giả sử file input.txt có nội dung Lorem Ipsum dài. Bạn có thể copy nội dung bất kỳ để kiểm tra.

2. Sử dụng mmap() để tạo file ánh xạ bộ nhớ

Có thể truyền tên file qua phương thức fileno() của đối tượng file hoặc os.open().

Lưu ý: Người dùng chịu trách nhiệm mở file trước khi gọi mmap() và đóng file sau đó.

Tham số thứ hai của mmap() là kích thước tính bằng byte chỉ định phần file được ánh xạ. Nếu giá trị là 0, toàn bộ file được ánh xạ. Có thêm tham số truy cập: ACCESS_READ (chỉ đọc), ACCESS_WRITE (ghi trực tiếp), ACCESS_COPY (copy-on-write).


import mmap

input_text = """Lorem ipsum dolor sit amet, causae apeirian ea his..."""  # Nội dung dài

input_file = 'input.txt'
# Tạo file đầu vào
with open(input_file, "w+") as f:
    f.write(input_text)

# Mở file chế độ đọc và ánh xạ
with open(input_file, 'r') as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        print(f"Output \n*** 5 byte đầu của {input_file}: {m.read(5)}")
        print(f"*** 10 byte tiếp theo: {m.read(10)}")

Kết quả:


*** 5 byte đầu của input.txt: b'Lorem'
*** 10 byte tiếp theo: b' ipsum dol'

3. Giải thích

Đọc file và ánh xạ vào bộ nhớ, dùng .read() đọc 5 byte đầu. Con trỏ file di chuyển 10 byte sau lần đọc đầu. Lần đọc tiếp theo read(10) trả về byte 6-15.

4. Cập nhật file tại chỗ (in-place)

Để thiết lập file ánh xạ bộ nhớ cho cập nhật, mở file chế độ 'r+' (không phải 'w') trước khi ánh xạ.

Ví dụ: sửa đổi một từ giữa dòng.


import mmap
import shutil

input_file = 'input.txt'
input_copy = input_file.replace('input', 'input_copy')
# Sao chép file để giữ nguyên gốc
shutil.copyfile(input_file, input_copy)

word = b'ipsum'
modified_word = word[::-1]  # Đảo ngược: 'muspi'

with open(input_copy, 'r+') as f:
    with mmap.mmap(f.fileno(), 0) as m:
        print(f"output \n *** Dòng trước cập nhật \n {m.readline().rstrip()}")
        
        # Quay lại đầu file
        m.seek(0)
        
        # Tìm từ và thay thế
        loc = m.find(word)
        m[loc:loc + len(word)] = modified_word
        m.flush()
        
        # Quay lại đầu và đọc lại
        m.seek(0)
        print(f" \n *** Dòng sau cập nhật \n {m.readline().rstrip()}")
        
        f.seek(0)
        print(f" \n *** File cuối cùng \n {f.readline().rstrip()}")

Kết quả: Từ "ipsum" bị thay bằng "muspi" cả trong bộ nhớ và file đĩa.

5. Chỉ thay đổi trong bộ nhớ (ACCESS_COPY)

Nếu chỉ muốn thấy thay đổi trong bộ nhớ, không cập nhật file đĩa, dùng ACCESS_COPY.


with open(input_copy, 'r+') as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY) as m:
        print(f"output \n *** Dòng trước cập nhật \n {m.readline().rstrip()}")
        m.seek(0)
        loc = m.find(word)
        m[loc:loc + len(word)] = modified_word
        m.flush()
        m.seek(0)
        print(f" \n *** Dòng sau cập nhật (trong bộ nhớ) \n {m.readline().rstrip()}")
        f.seek(0)
        print(f" \n *** File đĩa (không đổi) \n {f.readline().rstrip()}")

Kết quả: Nội dung trong bộ nhớ thay đổi, nhưng file đĩa giữ nguyên.