带偏移量的递归目录迭代器

7

是否可以从特定点开始循环?

$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, $flags));

$startTime = microtime(true); 
foreach($iterator as $pathName => $file){

  // file processing here

  // after 5 seconds stop and continue in the next request
  $elapsedSecs = (microtime(true) - $startTime);
  if($elapsedSecs > 5)
     break;
}

但是,下一次请求如何从我的断点处恢复?

  1. 恢复处理的项目数量;如果未设置,则将其初始化为零;
  2. 进入循环,跳过已处理的项目数量;
  3. 处理一个项目;
  4. 计数;
  5. 中断循环;
  6. 将值传递给下一个请求(使用会话或查询字符串)。反复执行此操作。
- axiac
1个回答

2

a) 将时间计算从foreach循环中分离出来。您有一个开始时间,并且想要运行5秒钟,因此您可以预先计算出结束时间(startime+5s)。在foreach内部,仅需比较时间是否大于或等于结束时间,然后跳出。

b) 问:是否可能从某个特定点开始循环?如何在下一个请求中恢复中断点?

我想到了两种方法。

您可以存储最后处理的位置和迭代器,并在最后一点+1处恢复。 在下一个请求时,通过调用iterator->next()直到达到要处理的下一个项目$lastPosition+1,快速将迭代器前进到上次迭代的最后位置。我们必须存储迭代器和lastPosition,并在下一个请求中同时获取两者,直到lastPosition等于迭代器中元素的总数。

或者,您可以在第一次运行时将迭代器转换为数组:$array = iterator_to_array($iterator);,然后使用减少数组的方法。 (也许其他人知道如何减少迭代器对象。) 使用这种方法,您只需要存储数据,每次请求都会逐渐减少,直到为0。

代码未经测试。这只是一个快速草稿。

$starttime = time();
$endtime = $starttime + (5 * 60); // 5sec
$totalElements = count($array);

for($i = 0; $i <= $totalElements; $i++) 
{
    if(time() >= $endtime) {
        break;
    }

    doStuffWith($array[$i]);
}

echo 'Processed ' . $i . ' elements in 5 seconds';

// exit condition is "totalElements to process = 0"
// greater 1 means there is more work to do
if( ($totalElements - $i) >= 1) {

    // chop off all the processed items from the inital array
    // and build the array for the next processing request
    $reduced_array = array_slice(array, $i);

    // save the reduced array to cache, session, disk    
    store($reduced_array);
} else {
    echo 'Done.';
}

// on the next request, load the array and resume the steps above...

总之,这是批处理,可能更有效地通过工作人员/作业队列来完成,例如:

1
谢谢,我会尝试使用Gearman。我考虑将整个数组存储在某个地方,但在某些情况下,它可能达到20万个元素,我相信这会消耗PHP很多资源。 - nice ass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接