Потребление памяти PHP-генераторами

285
28 февраля 2017, 18:55

В документации говорится:

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

Наглядным примером вышесказанного может послужить использование функции range() как генератора. Стандартная функция range() должна генерировать массив, состоящий из значений, и возвращать его, что может послужить результатом генерации огромных массивов: например, вызов range(0, 1000000), приведёт к использованию более чем 100 МБ памяти.

В качестве альтернативы мы можем создать генератор xrange(), который использует память только для создания объекта Iterator и сохранения текущего состояния, что потребует не больше 1 килобайта памяти.

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate. Instead, you can write a generator function, which is the same as a normal function, except that instead of returning once, a generator can yield as many times as it needs to in order to provide the values to be iterated over.

A simple example of this is to reimplement the range() function as a generator. The standard range() function has to generate an array with every value in it and return it, which can result in large arrays: for example, calling range(0, 1000000) will result in well over 100 MB of memory being used.

As an alternative, we can implement an xrange() generator, which will only ever need enough memory to create an Iterator object and track the current state of the generator internally, which turns out to be less than 1 kilobyte.

И приводится пример:

function xrange($start, $limit, $step = 1) {
    if ($start < $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be +ve');
        }
        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be -ve');
        }
        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}
/*
 * Note that both range() and xrange() result in the same
 * output below.
 */
echo 'Single digit odd numbers from range():  ';
foreach (range(1, 9, 2) as $number) {
    echo "$number ";
}
echo "\n";
echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
    echo "$number ";
}

Я увеличил количество генераций до 100000:

  • range(): https://repl.it/Fy4I;
  • xrange(): https://repl.it/Fy4K.

Результат мало чем отличается. Я полагал, что при использовании xrange() памяти должно быть потреблено меньше. Почему так?

Answer 1

Потому, что вы забыли использовать результат

Надо так:

$a=range(0, 100000);

4474.390625

https://repl.it/Fy4I/1

Создался полный набор значений.

$a=xrange(0, 100000);

377.7890625

https://repl.it/Fy4K/1

Извлечено только одно значение.

READ ALSO
Определение браузера способами php

Определение браузера способами php

Здрасьте всем, я мало что знаю в php, поэтому и спрашиваюЯ нашел вот эту функцию:

523
Замена пробелов на перенос строки в файле средствами php

Замена пробелов на перенос строки в файле средствами php

Есть txt файл в котором есть некий текст:

391
ffpmeg не вырезает видео

ffpmeg не вырезает видео

На локальном сервере работала эта команда:

234