在PHP foreach循环中需要更快的速度

时间:2011-10-09 17:46:50

标签: php

我正在对基于MS的Web应用程序进行一些集成,这迫使我通过SOAP将数据提取到我的php应用程序,这很好。

我在xml中获得了一个文件系统的结构,我将其转换为一个对象。所有文档都有ID和路径。为了能够将文档放在树视图中,我已经构建了一些方法来通过文件和文件夹结构来计算文档的位置。这工作正常,直到我开始尝试使用大文件列表。

我需要的是比foreach循环更快的方法(或做事方式)。

以下方法是麻烦制造者。

/**
 * Find parent id based on path
 * @param array $documents
 * @param string $parentPath
 * @return int 
 */
private function getParentId($documents, $parentPath) {
    $parentId = 0;
    foreach ($documents as $document) {
        if ($parentPath == $document->ServerUrl) {
            $parentId = $document->ID;
            break;
        }
    }
    return $parentId;
}
// With 20 documents nested in different folders this method renders in 0.00033712387084961
// With 9000 documents nested in different folders it takes 60 seconds

发送给对象的数组如下所示

Array
(
    [0] => testprojectDocumentLibraryObject Object
        (
            [ParentID] => 0
            [Level] => 1
            [ParentPath] => /Shared Documents
            [ID] => 163
            [GUID] => 505d70ea-51d7-4ef0-bf79-8e912553249e
            [DocIcon] => 
            [FileType] => 
            [Title] => Folder1
            [BaseName] => Folder1
            [LinkFilename] => Folder1
            [ContentType] => Folder
            [FileSizeDisplay] => 
            [_UIVersionString] => 1.0
            [ServerUrl] => /Shared Documents/Folder1
            [EncodedAbsUrl] => http://dev1.example.com/Shared%20Documents/Folder1
            [Created] => 2011-10-08 20:57:47
            [Modified] => 2011-10-08 20:57:47
            [ModifiedBy] => 
            [CreatedBy] => 
            [_ModerationStatus] => 0
            [WorkflowVersion] => 1
        )
...

这里有一个更大的数据阵列示例 http://www.trikks.com/files/testprojectDocumentLibraryObject.txt

感谢您的帮助!

=== UPDATE ===

为了说明不同东西的时间,我添加了这部分。

  1. 以8.5031080245972秒下载的数据包
  2. 在1.2838368415833秒内解码的数据包
  3. 数据包解压缩在0.051079988479614秒
  4. 列出以3.8216209411621秒组织的数据
  5. 标准属性填写0.46236896514893秒
  6. 自定义属性填写40.856066942215秒
  7. TOTAL:此页面创建于55.231353998184秒!
  8. 现在,这是一个自定义属性动作,我正在描述,其他的东西已经有所优化。从WCF服务发送的数据是压缩和编码的比率10:1(如10mb未压缩:压缩1mb)。

    当前优先级是优化自定义属性部分,其中getParentId方法占用99%的执行时间!

3 个答案:

答案 0 :(得分:3)

使用XMLReader或expat而不是simplexml可能会看到更快的结果。这两个都按顺序提供了xml,并且不会将整个文档存储在内存中。

同时确保你有APC扩展,对于实际的循环来说,这是一个很大的区别。实际循环的一些基准测试会很好。

最后,如果你不能让它更快......而不是试图优化读取大型xml文档,你应该研究这种“慢”不是问题的方法。一些想法包括异步过程,适当的缓存等。

修改

你实际上是为每个文件调用getParentId吗?这只是发生在我身上。如果你有1000个文件,那么这意味着已经有1000 * 1000个循环。如果确实如此,则需要重写代码,使其成为一个循环。

答案 1 :(得分:1)

你是如何首先填充数组的?也许您可以将项目排列在嵌套数组的层次结构中,其中每个键与路径的一部分相关。

e.g。

['Shared Documents']
    ['Folder1']
        ['Yet another folder']
            ['folderA']
            ['folderB']

然后在您的getParentId()方法中,提取路径的各个部分,然后搜索该部分数据:

private function getParentId($documents, $parentPath) {
    $keys = explode('/', $parentPath);

    $docs = $documents;
    foreach ($keys as $key) {
        if (isset($docs[$key])) {
            $docs = $docs[$key];
        } else {
            return 0;
        }
    }

    foreach $docs as $document) {
        if ($parentPath == $document->ServerUrl) {
            return $document->ID;
        }
    }
}

我还没有完全检查过你会做什么,但它可能会帮助你走上一条有用的道路。

编辑:我错过了你最初没有自己填充阵列;但提前做某种索引可能仍然可以节省你的整体时间,特别是如果多次在同一数据上调用getParentId

答案 2 :(得分:0)

像往常一样,这是编程设计的问题。从中可以汲取一些教训。

在文件系统中,父文件始终是一个文件夹,为了加快php中的这个过程你可以将所有文件夹放在一个单独的数组中,并将相应的ID作为密钥,并在你想找到父文件时搜索该数组一个文件,而不是搜索整个文件结构数组!

  1. 在6.9351849555969秒下载的数据包
  2. 在1.2411289215088秒内解码的数据包
  3. 数据包解压缩0.04874587059021秒
  4. 以3.7993721961975秒组织的列表数据
  5. 标准属性填写0.4488160610199秒
  6. 自定义属性填写0.15889382362366秒
  7. 本页创建于11.578738212585秒!
  8. 比较原始帖子

    中的自定义属性

    干杯