mmap () по сравнению с чтением блоков

172
задан isomorphismes 16 June 2016 в 03:59
поделиться

9 ответов

Основная стоимость производительности будет диском i/o. "mmap ()", конечно, более быстр, чем istream, но различие не могло бы быть примечательным, потому что диск i/o будет доминировать над Вашим временем выполнения.

я попробовал фрагмент кода Ben Collins (см. выше/ниже) протестировать его утверждение, которое "mmap () путь быстрее" и не нашло измеримого различия. См. мои комментарии к его ответу.

я был бы, конечно не , рекомендуют отдельно mmap'ing каждую запись в свою очередь, если Ваши "записи" не огромны - который был бы ужасно медленным, требуя 2 системных вызовов каждой записи и возможно теряя страницу из кэша памяти на дисках.....

В Вашем случае я думаю mmap (), istream и открытый низкий уровень () / чтение (), вызовы все будут о том же. Я рекомендовал бы mmap () в этих случаях:

  1. существует произвольный доступ (не последователен) в файле, И
  2. все это подходит удобно к памяти ИЛИ существует местность ссылки в файле так, чтобы определенные страницы могли быть отображены в и другие планировавшие страницы. Тем путем операционная система использует доступную RAM для максимального преимущества.
  3. ИЛИ если несколько процессов читают/работают на том же файле, то mmap () является фантастическим, потому что процессы все поделятся теми же физическими страницами.

(btw - я люблю mmap ()/MapViewOfFile ()).

44
ответ дан Tim Cooper 23 November 2019 в 20:39
поделиться

mmap путь быстрее. Вы могли бы записать простой сравнительный тест для доказательства его себе:

char data[0x1000];
std::ifstream in("file.bin");

while (in)
{
  in.read(data, 0x1000);
  // do something with data
}

по сравнению с:

const int file_size=something;
const int page_size=0x1000;
int off=0;
void *data;

int fd = open("filename.bin", O_RDONLY);

while (off < file_size)
{
  data = mmap(NULL, page_size, PROT_READ, 0, fd, off);
  // do stuff with data
  munmap(data, page_size);
  off += page_size;
}

Очевидно, я не учитываю детали (как то, как определить, когда Вы достигаете конца файла, если Ваш файл не является несколькими из page_size, например), но это действительно не должно быть намного более сложно, чем это.

, Если Вы можете, Вы могли бы попытаться разбить свои данные в несколько файлов, которые могут быть mmap () - редактор полностью вместо частично (намного более простого).

Несколько месяцев назад у меня была непродуманная реализация раздвижного окна mmap () - потоковый класс редактора для boost_iostreams, но никто не заботился, и я начал действовать с другим материалом. Больше всего, к сожалению, я удалил архив старых незаконченных проектов несколько недель назад, и это было одной из жертв:-(

Обновление : Я должен также добавить протест, что этот сравнительный тест выглядел бы очень отличающимся в Windows, потому что Microsoft реализовала изящный кэш файла, который делает большую часть того, что Вы сделали бы с mmap во-первых. Т.е. для часто полученных доступ файлов, Вы могли просто сделать станд.:: ifstream.read () и это было бы с такой скоростью, как mmap, потому что кэш файла уже сделает размещение в ОЗУ для Вас, и это прозрачно.

Заключительное Обновление : Посмотрите, люди: через большое количество различных комбинаций платформы ОС и стандартных библиотек и дисков и иерархий памяти, я не могу сказать наверняка, что системный вызов mmap, просматриваемый как черный квадрат, всегда всегда всегда будет существенно быстрее, чем read. Это не было точно моим намерением, даже если мои слова могли бы быть истолкованы тот путь. В конечном счете, моя точка была то, что i/o с отображенной памятью обычно быстрее, чем основанный на байте i/o; это все еще верно . Если Вы находите экспериментально, что нет никакого различия между этими двумя, то единственное объяснение, которое кажется разумным мне, состоит в том, что Ваша платформа реализует размещение в ОЗУ под покрытиями способом, которое выгодно для производительности вызовов к read. Единственный способ быть абсолютно уверенным, что Вы используете i/o с отображенной памятью портативным способом, состоит в том, чтобы использовать mmap. Если Вы не заботитесь о мобильности, и можно полагаться на представляющие параметры целевых платформ, то использование read может подойти, не жертвуя в известной мере никакой производительностью.

Редактирование для чистки списка ответа: @jbl:

раздвижное окно mmap звучит интересным. Можно ли сказать немного больше об этом?

Уверенный - я писал библиотеку C++ для Мерзавца (libgit ++, если Вы будете), и я столкнулся с подобной проблемой к этому: Я должен был быть в состоянии открыть большие (очень большие) файлы и не иметь производительность быть общей собакой (как это будет с std::fstream).

Boost::Iostreams уже имеет mapped_file Источник, но проблема состояла в том, что это было mmap, проверяют с помощью ping-запросов целые файлы, который ограничивает Вас 2^ (wordsize). На 32-разрядных машинах 4 ГБ не являются достаточно большими. Весьма разумно ожидать иметь .pack файлы в Мерзавце, которые становятся намного больше, чем это, таким образом, я должен был считать файл в блоках, не обращаясь к регулярному файлу i/o. Под покрытиями [1 112], я реализовал Источник, который является более или менее другим представлением взаимодействия между [1 113] и std::istream. Вы могли также попробовать аналогичный подход, просто наследовавшись std::filebuf в mapped_filebuf и точно так же наследовавшись std::fstream в [1 118]. Это - взаимодействие между двумя, в которых это трудно разобраться. Boost::Iostreams имеет часть работы, сделанной для Вас, и она также обеспечивает рычаги для фильтров и цепочек, таким образом, я думал, что будет более полезно реализовать его тот путь.

42
ответ дан Ben Collins 23 November 2019 в 20:39
поделиться

Я сожалею, что Ben Collins потерял свои раздвижные окна mmap исходный код. Это было бы хорошо иметь в Повышении.

Да, отображая файл намного быстрее. Вы по существу используете подсистему виртуальной памяти ОС для ассоциативной памяти к диску и наоборот. Думайте об этом этот путь: если разработчики ядра ОС могли бы сделать его быстрее, они были бы. Поскольку выполнение так делает примерно все быстрее: базы данных, время начальной загрузки, времена загрузки программы, и так далее.

подход раздвижного окна действительно не является настолько трудным, поскольку несколько continguous страниц могут быть отображены сразу. Таким образом, размер записи не имеет значения, пока самая большая из любой единственной записи впишется в память. Важная вещь управляет бухгалтерией.

, Если запись не начинает на getpagesize () границу, Ваше отображение должно начаться на предыдущей странице. Длина отображенного региона расширяется от первого байта записи (округленный в меньшую сторону при необходимости до самого близкого несколько getpagesize ()) к последнему байту записи (окруженный к самому близкому несколько getpagesize ()). Когда Вы закончены, обработав запись, можно не отобразить () ее и идти дальше к следующему.

это все работает просто великолепно в соответствии с Windows слишком использующий CreateFileMapping () и MapViewOfFile () (и GetSystemInfo () для получения SYSTEM_INFO.dwAllocationGranularity---не SYSTEM_INFO.dwPageSize).

7
ответ дан mlbrock 23 November 2019 в 20:39
поделиться

mmap должен быть быстрее, но я не знаю сколько. Это очень зависит от Вашего кода. Если Вы используете mmap, лучше mmap целый файл сразу, который сделает Вас жизнью намного легче. Одна потенциальная проблема состоит в том, что, если Ваш файл больше, чем 4 ГБ (или на практике предел ниже, часто 2 ГБ) Вам будет нужна архитектура на 64 бита. Таким образом, при использовании 32 сред Вы, вероятно, не хотите использовать их.

Однако может быть лучший маршрут к улучшающейся производительности. Вы сказали , входной файл много раз сканируется , если можно считать его в одной передаче и затем быть сделаны с ним, который мог потенциально быть намного быстрее.

4
ответ дан Leon Timmermans 23 November 2019 в 20:39
поделиться

Я соглашаюсь, что mmap'd файловый ввод-вывод будет быстрее, но в то время как Ваше сравнительное тестирование кода, разве встречный пример не должен быть несколько оптимизирован?

Ben Collins записал:

char data[0x1000];
std::ifstream in("file.bin");

while (in)
{
    in.read(data, 0x1000);
    // do something with data 
}

я предложил бы также пробовать:

char data[0x1000];
std::ifstream iifle( "file.bin");
std::istream  in( ifile.rdbuf() );

while( in )
{
    in.read( data, 0x1000);
    // do something with data
}

И кроме того, Вы могли бы также попытаться делать размер буфера тем же размером как одна страница виртуальной памяти, в случае, если 0x1000 не является размером одной страницы виртуальной памяти на Вашей машине... По моему скромному мнению, файловый ввод-вывод mmap'd все еще побеждает, но это должно сделать вещи ближе.

3
ответ дан paxos1977 23 November 2019 в 20:39
поделиться

Возможно, необходимо предварительно обработать файлы, таким образом, каждая запись находится в отдельном файле (или по крайней мере что каждый файл является mmap-способным размером).

Также Вы могли сделать все шаги обработки для каждой записи, прежде, чем перейти на следующую? Возможно, это избежало бы некоторых IO наверху?

3
ответ дан Douglas Leeder 23 November 2019 в 20:39
поделиться

Это походит на хороший пример использования для многопоточности... Я думал бы, что Вы могли довольно легко установить один поток для чтения данных, в то время как другой (s) обрабатывают его. Это может быть способом существенно увеличить воспринятую производительность. Просто мысль.

1
ответ дан Pat Notz 23 November 2019 в 20:39
поделиться

По моему мнению, с помощью mmap () "просто" нетрудности разработчик от необходимости написать их собственный код кэширования. В простом, "прочитанном файл eactly однажды" случай, это не будет твердым (хотя, поскольку mlbrock указывает на тихое сохранение копии памяти в пространство процесса) но если Вы идете назад и вперед в файле или пропускаете биты и т.д, я полагаю, что разработчики ядра, вероятно, сделали лучшую реализацию задания, кэширующуюся, чем я могу...

2
ответ дан mike 23 November 2019 в 20:39
поделиться

Я думаю, что самое лучшее в mmap - это возможность асинхронного чтения с помощью:

    addr1 = NULL;
    while( size_left > 0 ) {
        r = min(MMAP_SIZE, size_left);
        addr2 = mmap(NULL, r,
            PROT_READ, MAP_FLAGS,
            0, pos);
        if (addr1 != NULL)
        {
            /* process mmap from prev cycle */
            feed_data(ctx, addr1, MMAP_SIZE);
            munmap(addr1, MMAP_SIZE);
        }
        addr1 = addr2;
        size_left -= r;
        pos += r;
    }
    feed_data(ctx, addr1, r);
    munmap(addr1, r);

Проблема в том, что я не могу найти правильный MAP_FLAGS, чтобы дать подсказку, что эту память следует синхронизировать из файла как можно скорее. Я надеюсь, что MAP_POPULATE дает правильную подсказку для mmap (т.е. он не будет пытаться загрузить все содержимое перед возвратом из вызова, а сделает это в асинхронном режиме с помощью feed_data). По крайней мере, он дает лучшие результаты с этим флагом, даже если в руководстве указано, что он ничего не делает без MAP_PRIVATE, начиная с 2.6.23.

1
ответ дан 23 November 2019 в 20:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: