如何将一个很长的内存密集型循环拆分为更小的块


How do I split a really long, memory intensive loop into smaller chunks

我有一个很长的内存密集型循环。我无法一次性运行它,因为我的服务器设置了执行时间限制,或者我的内存不足。

我想把这个循环分成更小的块。

我有一个想法,将循环分成更小的块,然后设置一个位置标头以使用新的启动条件重新加载脚本。

我的旧脚本(伪代码。我知道下面的缺点)

for($i=0;$i<1000;$i++)
{
  //FUNCTION
}

我的新脚本

$start=$_GET['start'];
$end=$start+10;
for($i=$start;$i<$end;$i++;)
{
   //FUNCTION
}
header("Location:script.php?start=$end");

但是,我的新脚本成功运行了几次迭代,然后出现服务器错误"重定向过多"

有没有办法解决这个问题?有人可以提出更好的策略吗?

我在共享服务器上,因此无法增加内存分配或脚本执行时间。

我想要一个PHP解决方案。

谢谢。

"太多

重定向"是浏览器错误,因此PHP解决方案是使用cURL或标准流加载初始页面并让它遵循所有重定向。不过,您必须在没有超时限制的情况下从计算机运行它(例如使用 CLI)

要考虑的另一件事是使用 AJAX。页面上的一段 JavaScript 将运行您的脚本,收集脚本的输出并确定是停止(计算结束)还是继续(从 X 开始)。这样你也可以创建一个漂亮的进度表;-)

您可能希望研究分叉子进程来完成这项工作。这些子进程可以在自己的内存空间中以较小的块执行工作,而父进程会触发多个子进程。这通常由Gearman处理,但可以不用。

看看 Dealnews 开发者网站上的 Forking PHP。它有一个库和一些示例代码来帮助管理需要生成子进程的代码。

通常,

如果我必须多次迭代某些内容并且它有相当数量的数据,我会使用"延迟加载"类型的应用程序,例如:

for($i=$start;$i<$end;$i++;)
{
   $data_holder[] = "adding my big data chunks!";
   if($i % 5 == 1){   
    //function to process data
    process_data($data_holder); // process that data like a boss!
    unset($data_holder); // This frees up the memory
   }
}
 // Now pick up the stragglers of whatever is left in the data chunk
 if(count($data_holder) > 0){
    process_data($data_holder);
 }

这样,您可以继续循环访问数据,但不会占用内存。您可以按块工作,然后取消设置数据、在块中工作、取消设置数据等。以帮助防止记忆。就执行时间而言,这取决于您必须执行多少/编写脚本的效率。

基本前提 - "以较小的块处理数据以避免内存问题。保持设计简单,保持快速。

你每 100 次迭代在循环中放置一个条件来休眠怎么样?

for ($i = 0; $i < 1000; $i++)
{
    if ($i % 100 == 0)
        sleep(1800) //Sleep for half an hour
}

首先,在不知道你在循环中做什么的情况下,很难告诉你实际解决问题的最佳方法。但是,如果你想执行一些需要很长时间的事情,我的建议是设置一个 cron 作业,让它一次确定一小部分。该脚本将记录停止的位置,下次启动时,它可以读取日志以了解从何处开始。


编辑:如果你对cron死心塌地,并且你不太关心用户体验,你可以这样做:

让页面加载类似于上面的 cron 作业。除非经过这么多秒或迭代,否则停止脚本。显示刷新元标记或 JavaScript 刷新。执行此操作,直到任务完成。

由于您的局限性,我认为您使用的方法可能可行。 可能是您的浏览器试图变得聪明,不让您重定向回您刚刚访问的页面。它可能试图防止无限循环。

你可以试试

  • 在两个相同(或别名)的脚本之间来回重定向。

  • 不同的浏览器。

  • 让您的脚本输出带有刷新标记的 HTML 页面,例如

    <meta http-equiv="refresh" content="1; url=http://example.com/script.php?start=xxx">