บทนำ
MMAP (Memory Mapping) เมื่อแมปกับไฟล์ จะใช้หน่วยความจำเสมือน (virtual memory) ของระบบปฏิบัติการ เพื่อเข้าถึงข้อมูลบนระบบไฟล์โดยตรง แทนที่จะใช้ I/O functions ปกติ ทำให้ประสิทธิภาพ I/O ดีกว่า เพราะไม่ต้อง system call ทุกครั้ง หรือ copy ข้อมูลระหว่าง buffers
ไฟล์ที่ memory-mapped สามารถจัดการได้เหมือน mutable strings หรือ file-like objects ขึ้นอยู่กับการใช้งาน MMAP รองรับเมธอดมากมาย: close(), flush(), read(), readline(), seek(), tell(), write() และทำงานกับ slice operations และ regular expressions ได้ดี
ขั้นตอนการทำงาน
1. เตรียมไฟล์ข้อความตัวอย่าง
สร้างไฟล์ input.txt ด้วยข้อความ Lorem Ipsum ยาวๆ
2. ใช้ mmap() สร้าง memory-mapped file
ส่ง filename ผ่าน fileno() ของ file object หรือ os.open() พารามิเตอร์ที่สองคือขนาด (bytes) ที่จะแมป ถ้าเป็น 0 จะแมปทั้งไฟล์ มีอาร์กิวเมนต์เพิ่มเติม: ACCESS_READ (อ่านอย่างเดียว), ACCESS_WRITE (เขียนทับ), ACCESS_COPY (copy-on-write)
import mmap
input_text = """Lorem ipsum dolor sit amet, causae apeirian ea his..."""
input_file = 'input.txt'
# create input file
f = open(input_file, "w+")
f.write(input_text)
f.close()
# Open file read-only, map entire file (0)
with open(input_file, 'r') as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
print(f"Output \n*** Output first 5 bytes of the {input_file} is {m.read(5)}")
print(f"*** Output Next 10 bytes of the {input_file} is {m.read(10)}")
ผลลัพธ์:
*** Output first 5 bytes of the input.txt is b'Lorem'
*** Output Next 10 bytes of the input.txt is b' ipsum dol'
3. อ่านต่อเนื่อง
หลัง read(5) file pointer จะอยู่ที่ byte ที่ 6 การ read(10) ครั้งต่อไปจะอ่าน byte ที่ 6-15
4. แก้ไขไฟล์แบบ In-place
เปิดไฟล์ mode 'r+' (ไม่ใช่ 'w') ก่อนแมป
import mmap
import shutil
input_file = 'input.txt'
input_copy = input_file.replace('input', 'input_copy')
shutil.copyfile(input_file, input_copy) # backup
word = b'ipsum'
modified_word = word[::-1] # reverse: 'muspi'
with open(input_copy, 'r+') as f:
with mmap.mmap(f.fileno(), 0) as m:
print(f"output \n *** Line before updates \n {m.readline().rstrip()}")
m.seek(0) # rewind
loc = m.find(word)
m[loc:loc + len(word)] = modified_word
m.flush()
m.seek(0)
print(f" \n *** Line after updates \n {m.readline().rstrip()}")
f.seek(0)
print(f" \n *** Final file \n {f.readline().rstrip()}")
ผลลัพธ์: คำว่า "ipsum" ถูกแทนที่ด้วย "muspi" ทั้งในหน่วยความจำและไฟล์จริง
5. แก้ไขเฉพาะในหน่วยความจำ (ไม่เขียนลงดิสก์)
ใช้ ACCESS_COPY
with open(input_copy, 'r+') as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY) as m:
# ... same logic ...
# การเปลี่ยนแปลงจะอยู่ใน memory เท่านั้น ไฟล์จริงไม่เปลี่ยน
สังเกตว่า ไฟล์จริงไม่เปลี่ยนแปลง ขณะที่ใน memory เปลี่ยนแล้ว
สรุป
MMAP ช่วยเพิ่มประสิทธิภาพ I/O อย่างมากเหมาะสำหรับไฟล์ขนาดใหญ่ ที่ต้องการ random access หรือแก้ไขบางส่วนโดยไม่ต้องโหลดทั้งไฟล์เข้าหน่วยความจำ