Замечания по поводу памяти для долго-работающих php-скриптов

Я хочу написать worker для beanstalkd на php, используя контроллер Zend Framework 2. Он запускается через интерфейс командной строки и будет работать вечно, запрашивая задания у beanstalkd, как в этом примере .

В простом псевдо-подобном коде:

while (true) {
    $data   = $beanstalk->reserve();

    $class  = $data->class;
    $params = $data->params;

    $job    = new $class($params);
    $job();
}

$jobздесь, конечно, есть __invoke()метод. Однако некоторые вещи в этих заданиях могут выполняться в течение длительного времени. Некоторые могут работать со значительным объемом памяти. Некоторые могли внедрить объект $beanstalk, чтобы самостоятельно запускать новые задания, или иметь экземпляр Zend\Di\Locatorдля извлечения объектов из DIC.

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

*)В beanstalk reserveявляется блокирующим вызовом, и если задание недоступно, этот рабочий процесс будет ждать, пока не получит ответ от beanstalk.

Мой вопрос:как php справится с этим в долгосрочной перспективе и должен ли я принять какие-то особые меры предосторожности, чтобы это не блокировалось?

Это я рассмотрел и может быть полезен (но, пожалуйста, исправьте, если я ошибаюсь, и добавьте больше, если возможно):

  1. Используйте gc_enable()перед запуском цикла
  2. Используйте gc_collect_cycles()в каждой итерации
  3. Unset $jobв каждой итерации
  4. Явно сбросить ссылки в __destruct()из$job

(NB:Обновление отсюда)

Я провел несколько тестов с произвольными заданиями. Задания, которые я включил, были :«простыми», просто установите значение; «longarray» — создать массив из 1000 значений; "режиссер",пусть цикл введет $pheanstalkи добавит три простых задания в очередь (, чтобы теперь была ссылка из задания на beanstalk); "locatoraware", где задается Zend\Di\Locatorи все типы заданий создаются (, но не вызываются ). Я добавил в очередь 10 000 заданий, а затем зарезервировал все задания в очереди.

Результаты для «простого задания» (потребление памяти на 1000 заданий приmemory_get_usage())

0:     56392
1000:  548832
2000:  1074464
3000:  1538656
4000:  2125728
5000:  2598112
6000:  3054112
7000:  3510112
8000:  4228256
9000:  4717024
10000: 5173024

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

["Producer"] => int(2431)
["LongArray"] => int(2588)
["LocatorAware"] => int(2526)
["Simple"] => int(2456)

Память:

0:     66164
1000:  810056
2000:  1569452
3000:  2258036
4000:  3083032
5000:  3791256
6000:  4480028
7000:  5163884
8000:  6107812
9000:  6824320
10000: 7518020

Код выполнения выше обновлен до этого:

$baseMemory = memory_get_usage();
gc_enable();

for ( $i = 0; $i <= 10000; $i++ ) {
    $data = $bheanstalk->reserve();

    $class = $data->class;
    $params = $data->params;

    $job = new $class($params);
    $job();

    $job = null;
    unset($job);

    if ( $i % 1000 === 0 ) {
        gc_collect_cycles();
        echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "
"; } }

Как все заметили, потребление памяти в php не используется и сведено к минимуму, но со временем увеличивается.

15
задан Jurian Sluiman 3 April 2012 в 21:07
поделиться