Вопрос по perl, random, linux – Производительность Linux / Perl Mmap
====================================================================

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

В качестве простого теста я просто отображаю файл (используя модуль perl Sys :: Mmap, используя подпрограмму «mmap», который, как я считаю, отображается непосредственно в лежащую в основе функцию C), и засыпаю процесс. При этом код тратит больше минуты, прежде чем возвращается из вызова mmap, несмотря на то, что этот тест ничего не делает - даже не читает - из файла mmap & ed.

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

Удивительно, но второй процесс также тратит много времени, прежде чем вернуться из вызова mmap, примерно в то же время, что и mmap в первый раз.

Я удостоверился, что MAP\_SHARED используется и что процесс, который отобразил файл в первый раз, все еще активен (что он не завершен и что mmap не был отображен).

Я ожидал, что mmapped-файл позволит мне предоставить нескольким рабочим процессам эффективный произвольный доступ к большому файлу, но если каждый вызов mmap требует сначала прочитать весь файл, это немного сложнее. Я не тестировал с использованием длительных процессов, чтобы увидеть, быстрый ли доступ после первой задержки, но я ожидал, что с помощью MAP\_SHARED и другого отдельного процесса будет достаточно.

Моя теория состояла в том, что mmap будет возвращать более или менее немедленно, и что linux будет загружать блоки более или менее по требованию, но поведение, которое я наблюдаю, является противоположным, указывая на то, что оно требует чтения всего файла при каждом вызове mmap.

Любая идея, что я делаю неправильно, или если я полностью неправильно понял, как должен работать mmap?

 нашел проблему. Как и предполагалось, ни Linux, ни Perl не были виноваты. Чтобы открыть и получить доступ к файлу, я делаю что-то вроде этого:

```
#!/usr/bin/perl
# Create 1 GB file if you do not have one:
# dd if=/dev/urandom of=test.bin bs=1048576 count=1000
use strict; use warnings;
use Sys::Mmap;

open (my $fh, "<test.bin")
    || die "open: $!";

my $t = time;
print STDERR "mmapping.. ";
mmap (my $mh, 0, PROT_READ, MAP_SHARED, $fh)
    || die "mmap: $!";
my $str = unpack ("A1024", substr ($mh, 0, 1024));
print STDERR " ", time-$t, " secondsnsleeping..";

sleep (6060);

 Если вы тестируете этот код, нет никаких задержек, подобных тем, которые я обнаружил в моем исходном коде, и после создания минимального образца (всегда делайте это, верно!) Причина внезапно стала очевидной.

 Ошибка была в том, что я в своем коде лечил$mh` скаляр в качестве ручки, что-то легкое и легко перемещаемое (читай: проходить по значению). Оказывается, это на самом деле длинная строка в ГБ, определенно не то, что вы хотите перемещать без создания явной ссылки (perl lingua для значения «указатель» / дескриптор). Так что, если вам нужно хранить в хэше или аналогичном, убедитесь, что вы храните`\$mh, и разыщите его, когда вам нужно использовать его как${$hash->{mh}}, обычно в качестве первого параметра в подстроке или аналогичном.



 вам не следует использовать Sys :: Mmap. Вы должны использовать PerlIO's [ММАП](http://perldoc.perl.org/PerlIO.html#:mmap) слой.

 Можете ли вы опубликовать код, который вы используете?



 mmap()s довольно ограничен (и варьируется от ОС к ОС). Помните об этом, если вы используете файлы объемом в несколько гигабайт и тестируете только на 64-битной системе. (Я бы предпочел написать это в комментарии, но у меня пока недостаточно репутации)



 

 Или попробуйте свой код в другой версии OS / perl.



 которая может помочь производительности, является использование 'madvise (2)'. вероятно, легче всего сделать это через Inline :: C. «madvise» позволяет сообщить ядру, каким будет ваш шаблон доступа (например, последовательный, случайный и т. д.).



 [Широкий Искатель](http://www.tbray.org/ongoing/When/200x/2007/10/30/WF-Results) для производительности perl с mmap. Но есть одна большая ловушка. Если ваш набор данных будет на классическом HD, и вы будете читать из нескольких процессов, вы можете легко получить произвольный доступ, и ваш IO упадет до недопустимых значений (20 ~ 40 раз).



 : Mmap или PerlIO ": mmap" прекрасно работает в perl, но только до 2 ГБ файлов (магическое ограничение 32 бита). Если размер файла превышает 2 ГБ, появляются следующие проблемы:

 Использование Sys :: Mmap и substr для доступа к файлу, кажется, что substr принимает только 32-битное int для параметра position, даже в системах, где perl поддерживает 64-битную. Об этом написано как минимум одно сообщение об ошибке:

 [# 62646: максимальная длина строки с substr](http://rt.perl.org/rt3//Public/Bug/Display.html?id=62646)

С помощьюopen(my $fh, "<:mmap", "bigfile.bin")`, если размер файла превышает 2 ГБ, кажется, что perl либо зависнет, либо настаивает на чтении всего файла при первом чтении (не уверен, что, я никогда не запускал его достаточно долго, чтобы увидеть, завершен ли он), что приводит к смерти низкая производительность.

 Я не нашел обходного пути ни к одному из них, и в настоящее время я застрял с медленными (не mmap) операциями над файлами для работы с этими файлами. Если я не найду обходного пути, мне, возможно, придется реализовать обработку на C или другом языке более высокого уровня, который лучше поддерживает mmap для больших файлов.



 я бы посоветовал использовать[File :: Карта](http://search.cpan.org/perldoc?File::Map) вместо того[Sys :: MMAP](http://search.cpan.org/perldoc?Sys::Mmap). Это намного проще в использовании и менее подвержено сбоям, чем Sys :: Mmap.



 чтобы оправдать полный mmap. Если ваше использование не распределяется равномерно, вам, вероятно, лучше поискать, прочитать в недавно выделенную область и обработать, освободить, промыть и повторить. И работать с кусками, кратными 4k, скажем, 64k или около того.

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