2011-10-09 127 views
2

我正在对基于MS的Web应用程序进行一些整合,这迫使我通过SOAP将数据提取到我的PHP应用程序,这很好。在PHP foreach循环中需要更多速度

我在一个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秒解压在3.8216209411621秒组织
  4. 列表数据
  5. 标准特性填补了0.46236896514893秒
  6. 定制解码物业填写40.856066942215秒
  7. 总计:本页面创建时间55.231353998184秒!

现在,这是一个自定义属性操作,即时消息描述,其他的东西已经有所优化。从WCF服务发送的数据是压缩和编码比例10:1(如10mb未压缩:1mb压缩)。

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

+0

需要更快的速度?要么得到更好的硬件,要么切换到更快的语言。考虑到PHP是[最慢的语言之一](http://shootout.alioth.debian.org/u32/which-programming-languages-are-fastest.php),这不应该是一项艰巨的任务。 – NullUserException

+0

好吧,我同意你的意见。但在这种情况下,我没有选择。具有相同规格的服务器上的C#中的“相同”方法在不到2秒的时间内运行相同的数据。 –

+0

听起来不太可能。 PHP循环并不是很快,但是你的做法并不多。 SOAP解包和对象树生成的可能性比较慢。 - 如果你多次运行你的函数,并且忘记在你的问题中提及关键细节,建议单独构建一个单独的 - > ServerURL到 - > ID数组映射*,然后用它来代替。 – mario

回答

0

像往常一样,这是一个编程设计问题。从中可以学到一些经验教训。

在一个文件系统中,父文件总是一个文件夹,为了加快php中的这个过程,你可以把所有的文件夹放在一个单独的数组中,并将其相应的ID作为关键字,并在你想查找而不是搜索整个文件结构数组!

  1. 包在6.9351849555969秒下载
  2. 包在1.2411289215088秒
  3. 包在0.04874587059021秒解压在3.7993721961975秒组织
  4. 列表数据
  5. 标准特性填补了0.4488160610199秒
  6. 定制解码物业填写0.15889382362366秒
  7. 本页面创建于11.578738212585秒!

比较由一个自定义属性从我原来的职位

干杯

3

通过使用XMLReader或expat而不是simplexml,您可能会看到更快的结果。这两种方法都需要顺序执行xml,并且不会将整个文档存储在内存中。

此外,请确保您有APC扩展,对于实际循环来说,这是一个很大的区别。在实际循环的一些基准将会很好。

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

编辑

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

+0

很好的答案。 –

+0

谢谢,这很聪明。但是当im在那个部分时,xml已经在可以使用的对象中了。你所描述的是我在帖子底部添加的流程中的第四点。这是我的第二优先考虑,但现在不是真正的问题。感谢您的建议,但+1! –

+0

以字节为单位的实际xml文档有多大? – Evert

1

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

例如

['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