减少 PHP 中递归函数的内存使用

Fab*_*ção 3 php recursion

我在 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);
   }
}
Run Code Online (Sandbox Code Playgroud)

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

IMS*_*SoP 6

为了扩展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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

unset($api)user3720435的建议是在递归之前添加:

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

这告诉 PHP 您不再需要该内存,因此当它递归时,它不会增加。您仍然会构建$index和的多个副本$offset,但相比之下这些副本可能非常小。

话虽如此,目前还不清楚为什么这里需要递归。整个事情实际上可以改为一个简单的循环:

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

do..while 循环始终执行一次,然后不断重复,直到条件变为 false。展开后是这样的:

// 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
Run Code Online (Sandbox Code Playgroud)

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