【问题标题】:PHP substr() REALLY slow when not taking first part of string不获取字符串的第一部分时,PHP substr() 真的很慢
【发布时间】:2013-10-14 12:31:42
【问题描述】:

我有一个文本文件,它有大约 5,000 行,每行大约 200 个字符长。每行实际上包含 6 条不同的数据,我一直在使用 substr() 来分解它们。例如,在每一行中,字符 0 - 10 包含 Client#,字符 10-20 包含 Matter#,等等。这一切都很好,运行速度比我需要的要快。

当我的老板告诉我客户编号有 4 个前导零并且需要去掉它们时,我的问题就出现了。所以我想,没问题 - 我刚刚将我的第一个 substr() 函数从 substr(0, 10) (从 0 开始并占用 10 个字符)更改为 substr(4, 6) (从第 4 个字符开始,只占用 6 个字符),它将跳过4 个前导零,我会很高兴的。

但是,当我将 substr(0, 10) 更改为 substr(4,6) 时,该过程会停止并需要 永远 才能完成。这是为什么呢?

这是我的代码中的一个 sn-p:

// open the file    
$file_matters = fopen($varStoredIn_matters,"r") or exit("Unable to open file!");

// run until the end of the file
while(!feof($file_matters))
{
    // place current line in temp variable
    $tempLine_matters = fgets($file_matters);

    // increment the matters line count
    $linecount_matters++;

    // break up each column
    $clientID = trim(substr($tempLine_matters, 0, 10)); // THIS ONE WORKS FINE
    //$clientID = trim(substr($tempLine_matters, 4, 6)); // THIS ONE MAKES THE PROCESS GRIND TO A HALT!!
    $matterID = trim(substr($tempLine_matters, 10, 10)); 
    //$matterID = trim(substr($tempLine_matters, 15, 5)); 
    $matterName = trim(substr($tempLine_matters, 20, 80)); 
    $subMatterName = trim(substr($tempLine_matters, 100, 80)); 
    $dateOpen = trim(substr($tempLine_matters, 180, 10)); 
    $orgAttorney = trim(substr($tempLine_matters, 190, 3)); 
    $bilAttorney = trim(substr($tempLine_matters, 193, 3)); 
    $resAttorney = trim(substr($tempLine_matters, 196, 3)); 
    //$tolCode = trim(substr($tempLine_matters, 200, 3)); 
    $tolCode = trim(substr($tempLine_matters, 200, 3)); 
    $dateClosed = trim(substr($tempLine_matters, 203, 10)); 

    // just does an insert into the DB using the variables above

}

【问题讨论】:

  • 你确定是那个吗? IE。它适用于较小的数据文件吗?什么是错误?时间限制?
  • 我无法理解。根据实施,它不应该有真正的区别吗?
  • @AlmaDoMundo 我几乎肯定是这样的 - 较小的数据文件(即 200 行)处理没有问题。我在大约 2 分钟时超时,因为这是在我们的 PHP 配置中在我们的服务器上设置的最大执行时间。如果我将substr(4, 6) 改回substr(0, 10),它将在大约 3 秒内运行 5,000 行。
  • @bwoebi 我知道!这就是让我如此沮丧的原因!
  • @FastTrack 我无法重现...? $s = str_repeat("1", 1 << 16); $t = microtime(1); for ($i = 0; $i < 500000; $i++) trim(substr($s, 4, 6)); print (microtime(1) - $t)."s\n"; => 1.41551303863525s$s = str_repeat("1", 1 << 16); $t = microtime(1); for ($i = 0; $i < 500000; $i++) trim(substr($s, 0, 10)); print (microtime(1) - $t)."s\n"; => 1.42793393135071s

标签: php string substring


【解决方案1】:

我不明白为什么会这么慢,但你可以看看unpack,它可以一次提取你的固定宽度记录:

 $fields = unpack('A10client/A10matter/A60name ...etc... ',$tempLine_matters);

我使用与您的示例类似的记录模式进行了快速基准测试,发现 unpack 的速度是每次迭代中使用 10 个 substr 调用的两倍多。

我建议使用 xdebug 分析您的代码,以了解不同之处的真正所在。

【讨论】:

  • 我对 substr 进行了基准测试,以尝试重复您的发现,但没有成功。您的缓慢是否可能归因于其他一些操作需要更长的时间,因为 $clientID 与预期不符?
  • 非常有趣 - 我从未使用过unpack(),但我会在几分钟后在这里尝试一下。顺便说一句,你用什么来测试你的 PHP 脚本?我在这里看到了很多方法......
【解决方案2】:

这不是一个非常优化的过程。你也许应该多考虑一下。 但如果它现在起作用,那是最重要的...... 也许如果您通过两个过程获得价值,它会更快。例如:

$clientID_bis = trim(substr($tempLine_matters, 0, 10));
$clientID = trim(substr($clientID_bis, 4, 6)); 

【讨论】:

  • 你知道吗,我试过这个,以为它会有所帮助 - 但我得到了 same 挂断,就像我刚刚做 substr(4, 6)
  • 这是非常奇怪的行为 :) 如果您评论所有其他行,只保留 clientId 的 substr,您会重现问题吗?您不能在 $tempLine_matters 上使用爆炸,以便将 substr 与较小的字符串一起使用?
猜你喜欢
  • 2020-06-06
  • 1970-01-01
  • 2011-01-28
  • 2012-08-05
  • 2021-01-13
  • 2016-06-13
相关资源
最近更新 更多