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

时间:2012-04-20 03:14:39

标签: php loops http-headers

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

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

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

MY OLD SCRIPT(Pseudocode。我知道下面的缺点)

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");

然而,我的新脚本成功运行了几次迭代,然后我收到服务器错误“Too many redirects”

有解决方法吗?有人可以提出更好的策略吗?

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

我想要一个PHP解决方案。

感谢。

6 个答案:

答案 0 :(得分:2)

“重定向太多”是一个浏览器错误,因此PHP解决方案是使用cURL或标准流来加载初始页面并让它遵循所有重定向。您必须从没有超时限制的计算机运行此程序(例如使用CLI)

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

答案 1 :(得分:0)

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


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

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

答案 2 :(得分:0)

一般情况下,如果我必须多遍迭代并且它有相当数量的数据,我使用“延迟加载”类型的应用程序,如:

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);
 }

通过这种方式,您可以继续遍历数据,但不会填满内存。您可以使用块,然后取消设置数据,处理块,取消设置数据等。以帮助防止内存。就执行时间而言,这取决于您需要做多少/编写脚本的效率。

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

答案 3 :(得分:0)

你如何在循环中将一个条件放入每100次迭代中休眠一次?

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

由于你有这些限制,我认为你使用的方法可行。可能是您的浏览器试图变得聪明,并且不允许您重定向您刚刚访问的页面。它可能试图阻止无限循环。

你可以尝试

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

  • 另一种浏览器。

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

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