解析许多小字符串还是一个大字符串 - 哪个更快?

3
在需要使用正则表达式解析大量字符串的情况下,考虑到相同的RegEx针将用于所有测试,哪种方法更快:
  1. 逐个测试数组中的每个字符串;
  2. 将所有内容合并为一个大字符串,然后进行一次测试?
我认为第二种方法比多次启动RegEx引擎来处理字符串数组要好。然而,在PHP(PCRE)中进行了一些测试后,这似乎是不正确的。

基准测试


我在 PHP 5.3 中制作了一个简单的基准 (源代码),并得到以下结果:

122185 次交互,在 5 秒内测试了数组中多个较小字符串

26853 次交互,在 5 秒内进行了单个大字符串测试

因此,我必须得出第一种方法快了多达 5 倍的结论。然而,我想请教权威答案来确认这一点;由于我不知道某些 PHP 优化,可能会错误地做出假设。
在使用正则表达式测试之前,将大字符串分割成片段是否总是更优化的解决方案,而不仅仅是在 PCRE 中?

preg_grep()

我认为这个函数不应该在这里考虑。这是一个基准测试,而不是优化问题。更不用说该函数是一种 PHP 特定的方法。此外,preg_match_all 返回所有匹配的子字符串,而 preg_grep 只指示哪些数组元素匹配。

正则表达式必须被编译。除非你正在编写一些丑陋而冗长的正则表达式,否则编译开销是影响时间差的主要原因。 - Marc B
@MarcB 我不明白。对于数组中的每个字符串调用RegEx函数时,编译开销应该比第二种方法更大,但它却快了5倍。 - caiosm1005
1
啊,抱歉。我把你的结果倒过来读了,以为它们是时间等价物(例如26853比122185短)。然而,如果你正在处理一个数组,那么不要在循环中使用preg_match。有preg_grep用于处理数组匹配。也许现在连接开销正在影响性能。尝试预先构建单块字符串,然后再进行测试。 - Marc B
问题可能是内存。为超级字符串分配大量空间可能会减慢系统速度,但我不确定字符串有多大或者你在任何情况下如何加载字符串。 - Gazzini
如果您有兴趣,我已经在我的帖子中提供了源代码 - http://pastebin.com/znW5jYY9。很不可能基准测试会使我的计算机超载。此外,我确保我的代码相当优化。 解析多个字符串确实比一个大字符串更快。 - caiosm1005
2个回答

3
你的基准测试有误。请看一下你代码中的这段内容:
while(time() - $TimeStart < 5)
    for($i = 0; $i < $Length; $i++, $Iterations++)
    {
        preg_match_all($RegEx, $Input[$i], $m);
    }
}

$Iterations 应该只在 while 循环中增加,而不是在 for 循环内部增加。将前者除以结果如下:

24437 iterations using array
26853 iterations using big string

在进行时间测量时,不应使用time()函数,应该使用microtime()函数以获得更高的准确性。

最后,这个基准测试并不完整,因为为了使两个测试结果相同,数组方法需要在每次迭代后执行array_merge()函数。此外,某些地方还需要将一个大字符串转换为数组,这也需要时间。


很奇怪...在我看来,我的代码基本上与你的相同。并排放置,我实在看不出有什么本质区别。http://pastebin.com/uQ0kS6G3(改编)我仍然发现数组方法比implode字符串方法快得多。 - caiosm1005
@caiosm1005,使用pcre的结果在较大的字符串上会变慢,这可能可以解释一些问题。尽管如此,在这一点上,grep选项可能是最好的选择。 - Ja͢ck
但是它与您代码中的相同字符串。为什么结果相反? - caiosm1005
@caiosm1005 这不是同样的代码...请检查我的更新答案。 - Ja͢ck
哎呀!你说得对,是我的错误 ;) 我稍后会更新我的答案。 - caiosm1005

1

绝对不要将所有目标字符串合并成一个。首先,这会破坏许多在较短字符串上正常工作的正则表达式。锚点,如^$\A\z,突然找不到匹配的内容。此外,那些严重依赖于像.* 或.*?`这样的东西的正则表达式,在短字符串上尽管效率低下但仍能正常运行,但在Frankenstring上使用时往往会变得灾难性缓慢。

但即使合并后的版本速度更快,又有何影响呢?你试过数组版本并发现它太慢了吗?这是一个相当激进的解决方案(如果这确实是一种解决方案);如果我是你,我会在遇到它可以解决的问题之前暂停实施它。


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