减少PHP中递归功能的记忆使用情况



我在PHP中具有递归功能,在API中它可以允许您一次恢复200条记录。

但是,由于此API具有很高的响应延迟,因此我们决定使用本地中间数据库,在此添加这些记录,并且将在网站上显示同样的记录。

但是,由于该API有30000多个记录递归功能,因此由于30000记录,它会消耗大量内存,因此必须递归地调用超过1500次,并且最终给出了著名的stackoverflow。

我想知道是否有一种手动方法可以通过再次调用它而不会失去其值来清除此功能的内存。

代码示例:

public function recursive ($index = 0, $offset = 200) {
   $api = GetConectApi ($index, offset)-> Getrecords ();
   foreach ($api $value) {
      \Here is my necessary loop
   }
   if (count ($API) > 0) {
      $this Recursive ($index + 200, $offset + 200);
   }
}

我想找到一种方法,当它调用递归函数再次消除了以前的分配而不会失去传递的参考值。

为了在User3720435的答案上展开,您每次运行该功能时都可以通过创建新的$api变量来使用大量内存。要了解为什么,让我们"展开"代码 - 想象它们都是按顺序编写的,没有函数调用:

$api1 = GetConectApi ($index1, offset1)-> Getrecords ();
foreach ($api1 => $value1) {
    // Here is my necessary loop
}
if (count ($api1) > 0) {
    // RECURSION HAPPENS HERE
    $index2 = $index1 + 200, $offset2 = $offset1 + 200
    $api2 = GetConectApi ($index, offset)-> Getrecords ();
    foreach ($api2 => $value2) {
        // Here is my necessary loop
    }
    if (count ($api2) > 0) {
        // RECURSE AGAIN, AND AGAIN, AND AGAIN
    }
}

请注意,我将所有变量重命名为$api1$api2等。这是因为每次运行该函数时,$api实际上是一个不同的变量。它在您的源代码中具有相同的名称,但并不代表同一存储器。

现在,PHP不知道您在创建$api2时不会再次使用$api1,因此必须将这两者都保持在内存中。当您最终获得越来越多的数据时,它需要越来越多的内存。

用户3720435的建议是在递归之前添加unset($api)

$api = GetConectApi ($index, offset)-> Getrecords ();
foreach ($api => $value) {
      // Here is my necessary loop
}
if (count ($api) > 0) {
      unset($api);
      // code as before
}

这告诉PHP您不再需要该内存,因此它恢复了,它不会堆积。您仍然会建立多个$index$offset的副本,但是相比之下,它们可能很小。

说的话,尚不清楚为什么您在这里完全需要递归。整个过程实际上可以更改为一个简单的循环:

do {
    $api = GetConectApi ($index, offset)-> Getrecords ();
    foreach ($api => $value1) {
       // Here is my necessary loop
    }
    $index = $index + $offset;
} while (count ($api) > 0)

a ..而循环始终执行一次,然后继续重复直到条件变为假。展开看起来像这样:

// do...
    $api = GetConectApi ($index, offset)-> Getrecords ();
    foreach ($api => $value1) {
       // Here is my necessary loop
    }
    $index = $index + $offset;
if (count ($api) > 0) { // while...
$api = GetConectApi ($index, offset)-> Getrecords ();
    foreach ($api => $value1) {
       // Here is my necessary loop
    }
    $index = $index + $offset;
}
if (count ($api) > 0) { // while...
// etc

请注意,我们不需要分配任何额外的内存,因为我们没有输入一个新功能 - 我们只是一遍又一遍地使用相同的变量。

您可以尝试在$ api变量上进行清理。

$cnt = count($api);
$api = null;
unset($api);
if ( $cnt > 0) {

您可以使用队列系统获取所有数据并将其保存到您的数据库中,例如RMQ

,或者您可以在DB中使用[索引],请说设置为0

然后,您添加cron作业以获取无递归中的API的数据,并且每分钟都会运行

它将转到DB获取索引,您有偏移并获取数据并增加索引

1分钟后,该作业将再次运行到DB获取索引,您有偏移量并获取数据并增加索引等等

最新更新