Почему mmap в python такой медленный?

#python #performance #io #mmap

#python #Производительность #io #mmap

Вопрос:

У меня есть файл бинарного примера объемом 1 ГБ, который я загружаю в память. При запуске бенчмарка на python 3.7 и Windows mmap сильно проигрывает в производительности readinto . Следующий код запускает тест. Первая процедура использует simple readinto для чтения первых N байтов файла в буфер, тогда как вторая процедура использует mmap просто для извлечения N байтов в память и чтения их тоже.

 import numpy as np
import time
import mmap
import os
import matplotlib.pyplot as plt

def mmap_perf():

    filepath = "test.bin"
    filesize = os.path.getsize(filepath)

    MEGABYTES = 10**6
    batch_size = 10 * MEGABYTES

    mview = memoryview(bytearray(filesize))

    batch_sizes = []
    load_durations = []
    for i_part in range(1, filesize // batch_size):

        start_time = time.time()
        with open(filepath, "br") as fp:
            # start = i_part * batch_size
            fp.seek(0)
            fp.readinto(mview[0:batch_size * i_part])
        duration_readinto = time.time() - start_time

        start_time = time.time()
        with open(filepath, "br") as fp:
            length = (i_part * batch_size // mmap.ALLOCATIONGRANULARITY   1) * 
                mmap.ALLOCATIONGRANULARITY
            with mmap.mmap(fp.fileno(),
                           offset=0,
                           length=length,
                           access=mmap.ACCESS_READ) as mp:
                mview[0:i_part * batch_size] = mp[0:i_part * batch_size]
        duration_mmap = time.time() - start_time

        msg = "{2}MBnreadinto: {0:.4f}nmmap:     {1:.4f}"
        print(msg.format(duration_readinto, duration_mmap, i_part * batch_size // MEGABYTES))

        batch_sizes.append(batch_size * i_part // MEGABYTES)
        load_durations.append((duration_readinto, duration_mmap))

    load_durations = np.asarray(load_durations)
    plt.plot(batch_sizes, load_durations)
    plt.show()
  

График выглядит следующим образом:

введите описание изображения здесь

Я просто не могу понять, как mmap полностью проигрывает, даже при загрузке небольших пакетов размером всего 10 МБ из файла объемом 1 ГБ.

Комментарии:

1. mmap это один из самых дорогих системных вызовов в Linux, и ошибка страницы при доступе к каждой следующей странице также увеличивает травму. Попробуйте использовать MAP_POPULATE .

2. Вы также можете попробовать использовать огромные страницы и большие блоки. Это может немного помочь. Обратите внимание, что параллельное выполнение ошибок страницы (очистка страницы) обычно выполняется быстрее (по крайней мере, в Linux).

Ответ №1:

При такой нагрузке на последовательное чтение системный вызов readinto through может в значительной степени выиграть от предварительной выборки ОС, в то время как вам, возможно, придется установить MAP_POPULATE для mmap, чтобы получить то же преимущество. Если вы протестируете нагрузку на случайное чтение, вы увидите совершенно другое сравнение.

Комментарии:

1. Спасибо за подсказку. Модуль Python mmap, похоже, явно не содержит флага, но имеет » рекомендации mmap «. Я попытаюсь выяснить, соответствует ли какой-либо из флагов MAP_POPULATE .