Я хочу написать 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 справится с этим в долгосрочной перспективе и должен ли я принять какие-то особые меры предосторожности, чтобы это не блокировалось?
Это я рассмотрел и может быть полезен (но, пожалуйста, исправьте, если я ошибаюсь, и добавьте больше, если возможно):
$job
в каждой итерации__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 не используется и сведено к минимуму, но со временем увеличивается.