73 линии погром - разбор, сортировка и сохранение в CSV в PHP в CLI


Внутри папка с именем в формате txt у меня 138 текстовые файлы (на общую сумму 349MB), полные адреса электронной почты. Я понятия не имею (пока), сколько адресов есть. Они отделены друг от друга разрывы строк. Я создал следующий скрипт, чтобы прочитать все эти файлы в массив, закрыть дубликаты, а затем сортировать по алфавиту и сохранить в группы 10тыс в CSV-файл. Он работает правильно, но он также работает на протяжении 8 часов (двухъядерный i3 с Ж/ 4 gigabizzles оперативной памяти, интерфейсом SATA 7200 HDD), что кажется чрезмерным для меня. Сверху также говорит мне, что мои программы загрузка ЦП 100% и это было все, пока он работает. Дать мой сценарий looksie и мне посоветовать, где я так ужасно неправильно.

function writeFile($fileName, $fileData)
{

    $writeFileOpen = fopen('csv/' . $fileName, 'w');
    fwrite($writeFileOpen, $fileData) or die('Unable to write file: ' . $fileName);
    fclose($writeFileOpen);

}

function openFiles()
{

    $addressList = array();
    $preventRepeat = array();

    if ($handle = opendir('txt')) {
        while (false !== ($file = readdir($handle))) {
            if ($file != '.' && $file != '..') {
                $newList = explode("\n", trim(file_get_contents('txt/' . $file)));
                foreach ($newList as $key => $val) {
                    $val = str_replace(array(',', '"'), '', $val);
                    if (in_array($val, $preventRepeat) || !strpos($val, '@') || !$val) {
                        unset($newList[$key]);
                    }
                    $preventRepeat[] = $val;
                }
                if (empty($addressList)) {
                    $addressList = $newList;
                } else {
                    $addressList = array_merge($addressList, $newList);
                }
                unset($newList);
            }
        }
        closedir($handle);
    } else {
        echo 'Unable to Read Directory';
    }

    $lineNum = 1;
    $fileNum = 1;
    $fileData = '"Email Address"' . "\n";

    sort($addressList);

    $lastKey = count($addressList) - 1;

    foreach ($addressList as $key => $val) {

        if ($lineNum > 10000) {

            writeFile('emailList-' . $fileNum . '.csv', trim($fileData));

            $lineNum = 1;
            $fileNum++;
            $fileData = '"Email Address"' . "\n";

        } elseif ($key == $lastKey) {

            writeFile('emailList-' . $fileNum . '.csv', trim($fileData));

            echo 'Complete';            

        }

        $fileData .= '"' . trim($val) . '"' . "\n";
        $lineNum++;

    }

}

openFiles();

ПС. Я написал этот сценарий в спешке, чтобы выполнить задачу. Я могу понять, если вы не считаете этот сценарий распределения достоин.

Редактировать: Итак, я приехал на работу сегодня, чтобы найти свой сценарий в какой-то момент превысил 536MB памяти и выйти на фатальную ошибку. Я уже увеличил свой ини файл memory_limit параметра от 128 МБ до 512 МБ. Это не обязательно отражают проблемы с самим скриптом. Я просто хотела поделиться своим разочарованием с задачей.



1293
4
задан 22 марта 2011 в 11:03 Источник Поделиться
Комментарии
3 ответа

Это было долгое время, так как я писал на PHP, но я думаю, что я могу дать тебе несколько советов, так или иначе.

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

if (in_array($val, $preventRepeat) || !strpos($val, '@') || !$val) {
...

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

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

// Store a certain address.
$addressList[$val] = true;

Проверив, присутствует ли значение для данного ключа указывает, является ли он уже был сохранен. Обратите внимание, как $preventRepeat могут быть удалены и все хранится в $addressList. Это удаляет потребность array_merge, что опять приводит к большей производительности.

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

Касающихся моих предыдущих комментариев:


Вы, вероятно, может сделать скрипт
уже в два раза быстрее за счет использования
оба ядра. Отдельной обработки
через два процесса, или использовать две
потоков. Я нахожу странным, что он
показывает загрузку процессора на 100% при
момент. Не так просто работать на одном
ядром?

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

2
ответ дан 23 марта 2011 в 02:03 Источник Поделиться

Это будет гораздо более эффективным:

$result = array();

if (($handle = opendir('./txt/')) !== false)
{
set_time_limit(0);
ini_set('memory_limit', -1);

while (($file = readdir($handle)) !== false)
{
if (($file != '.') && ($file != '..'))
{
if (is_resource($file = fopen('./txt/' . $file, 'rb')) === true)
{
while (($email = fgets($file)) !== false)
{
$email = trim(str_replace(array(',', '"'), '', $email));

if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false)
{
$result[strtolower($email)] = true;
}
}

fclose($file);
}
}
}

closedir($handle);

if (empty($result) !== true)
{
ksort($result);

foreach (array_chunk($result, 10000, true) as $key => $value)
{
file_put_contents('./emailList-' . ($key + 1) . '.csv', implode("\n", array_keys($value)), LOCK_EX);
}
}

echo 'Done!';
}

3
ответ дан 23 марта 2011 в 07:03 Источник Поделиться

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

Если вы просто попасть в ОС UNIX, а также проверить:


  • с помощью ImageMagick набор утилит, которые обеспечивают фантастический обработки изображений

  • этот файл (на основе libmagic), который обеспечивает правильный файл типа проверка загруженных файлов принятых от населения

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

1
ответ дан 12 апреля 2011 в 02:04 Источник Поделиться