0

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

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

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

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

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 解决方案。

谢谢。

4

6 回答 6

2

“重定向过多”是浏览器错误,因此 PHP 解决方案是使用 cURL 或标准流来加载初始页面并让它跟随所有重定向。您必须在没有超时限制的机器上运行它(例如使用 CLI)

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

于 2012-04-20T03:35:45.853 回答
1

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

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

于 2012-04-20T03:29:22.877 回答
0

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


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

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

于 2012-04-20T03:18:14.210 回答
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);
 }

这样你就可以继续遍历你的数据,但你不会填满你的内存。您可以分块工作,然后取消设置数据,分块工作,取消设置数据等。以帮助防止内存。至于执行时间,这取决于你必须做多少/编写脚本的效率。

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

于 2012-04-20T03:20:43.100 回答
0

您如何在循环中放置一个条件,使其每 100 次迭代休眠一次?

for ($i = 0; $i < 1000; $i++)
{
    if ($i % 100 == 0)
        sleep(1800) //Sleep for half an hour
}
于 2012-04-20T03:24:37.647 回答
0

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

你可以试试

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

  • 不同的浏览器。

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

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

于 2012-04-20T04:01:16.997 回答