我想使用Zend Framework 2控制器在php中为beanstalkd编写一个worker。它通过CLI启动,并将永远运行,要求从诸如this example等beanstalkd工作。长时间运行的PHP脚本的内存考虑因素
在简单的伪类似的代码:
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()在每次迭代中取消设置
$job
- 明确地取消设置
__destruct()
中的参考$job
(注:从这里更新)
我并运行一些测试任意工作。我包括的工作是:“简单”,只需设定一个值; “longarray”,创建一个包含1,000个值的数组; “生产者”,让循环注入$pheanstalk
并添加三个simplejob到队列(所以现在有一个从作业到豆茎的参考); “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 不杠杆和保持在最低限度,但随着时间的推移而增加。
这是一个有趣的问题,我添加了一些关于使用'gc_collect_cycles'的相关研究http://stackoverflow.com/questions/38850391/when-does-php-run-garbage-collection-in-long-running-scripts/ 38850392#38850392 – mcfedr 2016-08-29 12:10:54