Я хочу написать рабочий для 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 справится с этим в долгосрочной перспективе, и я должен принять какие-то особые меры предосторожности, чтобы это не блокировалось?
Это я рассмотрел и мог бы быть полезным (но, пожалуйста, исправьте, если я ошибаюсь, и добавьте больше, если это возможно):
- Используйте gc_enable () перед началом цикла
- Используйте gc_collect_cycles () в каждой итерации
- Unset
$job
в каждой итерации
- Явно сброшенные ссылки в
__destruct()
из $job
(примечание: обновление здесь)
Я провел несколько тестов с произвольными заданиями. Задания, которые я включил, были: «простые», просто установите значение; "longarray", создать массив из 1000 значений; «продюсер», пусть цикл внедрит $pheanstalk
и добавит три простых задания в очередь (так что теперь есть ссылка от задания на бобовый стебель); «locatoraware», где задано Zend\Di\Locator
и созданы все типы заданий (хотя и не вызваны). Я добавил в очередь 10 000 заданий, а затем зарезервировал все задания в очереди.
Результаты для "simplejob" (потребление памяти на 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, "<br>";
}
}
Как все замечают, потребление памяти в php не используется и поддерживается на минимуме, но увеличивается со временем.