Замедление в большом массиве perl

В настоящее время я запускаю программу на Perl, в которой мне нужно взять текстовый файл из 1 миллиона строк, разбить его на куски (где-то от 50 до 50 000 строк на кусок) и выполнить некоторые вычисления и тому подобное. Прямо сейчас я загружаю все данные в array1. Я беру array2 и использую его для извлечения только тех фрагментов данных, которые мне нужны. Затем я делаю то, что мне нужно, для массива 2, а затем возвращаюсь и беру следующий набор.

пример данных

А, бла1, бла2

А, бла6, бла7

А, бла4, бла5

Б, бла2, бла2

Так что я собирал первые три в массив 2, сортировал их, а затем переходил к следующему набору. Моя программа поначалу работает довольно хорошо и эффективно, но позже она сильно замедляется.

50 КБ занимает 50 секунд, 100 КБ занимает 184 секунды, 150 КБ занимает 360 секунд, 200 КБ занимает 581 секунду, и по мере выполнения программы становится только экспоненциально хуже (4500 секунд в строке 500 КБ).

Нет, я не могу использовать базу данных для этого проекта, есть предложения?

my @Rows1=<FILE>;
my $temp = @Rows1;
for($k = 0; $k < $temp; $k++)
{
    my @temp2array = ();
    my $temp2count = 0;
    my $thisrow = $Rows1[$k];
    my @thisarray = split(',', $thisrow);
    my $currcode = $thisarray[0];
    my $flag123 = 0;
    $temp2array[$temp2count] = $thisrow;
    $temp2count++;
    while ($flag123 == 0)
    {
        $nextrow = $tuRows1[$k + 1];
        @nextarray = split(',', $nextrow);
        if ($currcode eq $nextarray[0])
        {
            $temp2array[$temp2count] = $nextrow;
            $k++;
            $temp2count++;
        }
        else
        {
            $flag123 = 1;
        }
    }
}

Я отредактировал свой код, чтобы он больше походил на ответ ниже, и у меня есть такие времена:

50k = 42, 100k = 133, 150k = 280, 200k = 467, 250k = 699, 300k = 978, 350k = 1313

Это не совсем линейно, и по этой тенденции эта прога все равно будет занимать 14000+ секунд. Я исследую другие части кода


person ThePirateSheep    schedule 26.01.2011    source источник
comment
Было бы неплохо показать нам свой код и некоторые примеры входных данных.   -  person CanSpice    schedule 26.01.2011
comment
Я обновил свой вопрос, добавив хотя бы код получения данных из файла и секвестрирования их в собственном массиве. Перед этим есть примерные данные. Это просто строка с разделителями-запятыми, содержащая около 30 значений.   -  person ThePirateSheep    schedule 26.01.2011
comment
Что такое @tuRows1? Это должно быть @Rows1?   -  person ysth    schedule 26.01.2011
comment
Вы написали алгоритм художника Шлемейля.   -  person Ether    schedule 26.01.2011


Ответы (2)


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

В вашем случае вы, кажется, обрабатываете строки, которые имеют одинаковое значение в первом поле вместе, поэтому вы можете сделать что-то вроде:

my @lines = ();
my $current_key = '';

while (<FILE>) {
    my ($key) = split /,/;     # get first column
    if ($key ne $current_key) {
        # new key. Process all the lines from the previous key.
        if (@lines > 0) {
            process(@lines);
        }
        @lines = ();
        $current_key = $key;
    }
    push @lines, $_
}
# don't forget the lines from the last key
if (@lines > 0) {
    process(@lines);
}

Таким образом, вы сохраняете в памяти только столько строк, чтобы составить одну группу.

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

person mob    schedule 26.01.2011
comment
Сам файл изначально сортируется по первому значению, так что это не большая проблема. И я знаю, что загрузка всего файла - не лучшая практика в кодировании, но я просто не понимаю, почему он так сильно замедляется ПОСЛЕ того, как он уже загружен. Но я попробую что-то вроде этого - person ThePirateSheep; 26.01.2011
comment
Даже после загрузки большой набор данных будет разбросан по нескольким страницам виртуальной памяти. Доступ к этим данным потребует переключения страниц и замедлит работу. - person mob; 26.01.2011
comment
Поэтому я отредактировал свой код, чтобы он больше походил на код, который вы предоставили. Вместо того, чтобы читать весь файл, вытягивать строку за строкой, откладывать фрагмент, который мне нужно использовать, и т. д. Теперь он, похоже, работает более плавно, хотя все еще не молниеносно (чего, я знаю, не произойдет, мне просто нужно удалить экспоненциальный увеличение времени ожидания). Новые времена будут отредактированы в моем исходном сообщении - person ThePirateSheep; 26.01.2011

Просто запуск кода, который вы показываете, замедляет работу? Если нет, проблема заключается в коде, который фактически обрабатывает каждый фрагмент @temp2array, возможно, некоторые переменные все еще содержат данные, оставшиеся от предыдущих фрагментов.

person ysth    schedule 26.01.2011