Упускаемый из виду инструмент оптимизации производительности в PHP: генераторы

PHP

Если вы знакомы с Python или другими языками, вы должны быть знакомы с генераторами. Тем не менее, многие разработчики PHP могут не знать функции генератора, это может быть связано с тем, что генератор является функцией, представленной в PHP 5.5.0, или функция генератора не очень очевидна. Однако функция генератора действительно полезна.

преимущество

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

  • Генераторы могут оказать огромное влияние на производительность приложения PHP.
  • Экономьте много памяти при запуске PHP-кода
  • Больше подходит для обработки больших объемов данных

Итак, как именно работают эти магические функции? Сначала возьмем пример.

Введение концепции

Во-первых, давайте отбросим бремя концепции генератора и посмотрим на простую функцию PHP:

function createRange($number){
    $data = [];
    for($i=0;$i<$number;$i++){
        $data[] = time();
    }
    return $data;
}

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

  1. Создаем функцию.
  2. Функция содержитforЦикл, мы зацикливаем текущее время на$dataв
  3. forПосле выполнения цикла поместите$dataВернитесь назад.

Это не конец, продолжим. Давайте напишем еще одну функцию и выведем возвращаемое значение этой функции в цикле:

$result = createRange(10); // 这里调用上面我们创建的函数
foreach($result as $value){
    sleep(1);//这里停顿1秒,我们后续有用
    echo $value.'<br />';
}

Посмотрим на результаты в браузере:

Здесь все идеально, никаких проблем. (Конечноsleep(1)Эффекта не видно)

подумать о проблеме

Заметим, что при вызове функцииcreateRangeпри даче$numberПередано значение 10, очень маленькое число. Предположим, теперь передайте значение10000000(10 миллионов).

Тогда в функцииcreateRangeв,forЦикл должен быть выполнен100010 000 раз. и имеют100010 000 значений помещаются в$dataвнутри, пока$dataТеперь массивы размещаются в памяти. Таким образом, при вызове функции будет занимать много памяти.

Здесь в игру вступают генераторы.

Создать генератор

Мы модифицируем код напрямую, обратите внимание на следующее:

function createRange($number){
    for($i=0;$i<$number;$i++){
        yield time();
    }
}

Взгляните на этот код, который очень похож на тот, что был только что: мы удаляем массив$data, и тоже ничего не возвращает, но вtime()Ключевое слово использовалось ранееyield

использовать генератор

Давайте снова запустим второй фрагмент кода:

$result = createRange(10); // 这里调用上面我们创建的函数
foreach($result as $value){
    sleep(1);
    echo $value.'<br />';
}

Чудесным образом мы обнаружили, что выходное значение не такое, как в первый раз без использования генератора. Значения (временные метки) здесь отстоят друг от друга на 1 секунду.

Интервал в одну секунду здесь на самом делеsleep(1)последствия. Но почему нет интервала в первый раз? это потому, что:

  • Когда генераторы не используются:createRangeвнутри функцииforРезультат цикла быстро помещается в$data, и немедленно вернуться. так,foreachЦикл представляет собой фиксированный массив.
  • При использовании генераторов:createRangeЗначение не генерируется быстро за один раз, а зависит отforeachцикл.foreachцикл один раз,forВыполнить один раз.

На этом этапе вы должны иметь представление о генераторах.

Глубокое понимание генераторов

Анализ кода

Давайте проанализируем код прямо сейчас.

function createRange($number){
    for($i=0;$i<$number;$i++){
        yield time();
    }
}

$result = createRange(10); // 这里调用上面我们创建的函数
foreach($result as $value){
    sleep(1);
    echo $value.'<br />';
}

Восстановим процесс выполнения кода.

  1. первый звонокcreateRangeфункция, передача параметров10,ноforvalue выполняется один раз, затем останавливается и сообщаетforeachЗначения, которые можно использовать для первого цикла.
  2. foreachначать правильно$resultпетля, заходи первымsleep(1), затем начните использоватьforВыполняет вывод для заданного значения.
  3. foreachЧтобы подготовиться ко второму циклу, перед началом второго циклаforЦикл спрашивает снова.
  4. forЗатем цикл выполняется снова, сообщая сгенерированную метку времениforeach.
  5. foreachПолучите второе значение и выведите. потому чтоforeachсерединаsleep(1),так,forЦикл задерживается на 1 секунду для генерации текущего времени

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

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

концептуальное понимание

К этому моменту у вас должно быть общее представление о том, что такое генератор. Теперь поговорим о принципе генератора.

Сначала определите понятие:Ключевое слово генератора yield не является возвращаемым значением, его технический термин называется выходным значением, он просто генерирует значение.

тогда в кодеforeachЧто такое цикл? На самом деле, когда PHP использует генератор, он возвращаетGeneratorобъект класса.foreachЭтот объект можно повторять, каждую итерацию PHP будет проходитьGeneratorЭкземпляр вычисляет значение, которое необходимо повторить следующим образом. такforeachПросто знайте значение, которое необходимо повторить в следующий раз.

Более того, во время бегаforПосле выполнения цикла он немедленно останавливается. ждатьforeachснова в следующем цикле сforПри запросе следующего значенияforЦикл выполнится только один раз, а затем сразу же остановится. Не выполнять до тех пор, пока условие не будет выполнено.

актуальное приложение для разработки

Многие PHP-разработчики не понимают генераторы, главным образом потому, что они не понимают предметную область приложения. Итак, каковы применения генераторов в реальной разработке?

Чтение очень больших файлов

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

Здесь генератор можно использовать в полевых условиях. Просто посмотрите: Прочитайте текстовый файл

Мы создаем текстовый документ и вводим в него несколько строк текста для демонстрации чтения.

<?php
header("content-type:text/html;charset=utf-8");
function readTxt()
{
    # code...
    $handle = fopen("./test.txt", 'rb');

    while (feof($handle)===false) {
        # code...
        yield fgets($handle);
    }

    fclose($handle);
}

foreach (readTxt() as $key => $value) {
    # code...
    echo $value.'<br />';
}

Из вывода на приведенном выше рисунке видно, что код совершенно нормальный.

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

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

над

Порекомендуйте URL-навигацию для разработчиков, разработанную нашей командой:Навигация с помощью пера — создавайте самую краткую навигацию по веб-сайту с душой