isset()vs strlen() - 快速/清晰的字符串长度计算

Boz*_*Boz 55 php coding-style

我遇到了这段代码......

if(isset($string[255])) {
    // too long
}
Run Code Online (Sandbox Code Playgroud)

isset()比6到40快

if(strlen($string) > 255) {
    // too long
}
Run Code Online (Sandbox Code Playgroud)

isset()的唯一缺点是代码不清楚 - 我们无法立即知道正在做什么(参见pekka的回答).我们可以在一个函数中包装isset(),即strlt($ string,255),但我们会失去isset()的速度优势.

我们如何在保留代码可读性的同时使用更快的isset()函数?

编辑:测试显示速度http://codepad.org/ztYF0bE3

strlen() over 1000000 iterations 7.5193998813629
isset() over 1000000 iterations 0.29940009117126
Run Code Online (Sandbox Code Playgroud)

EDIT2:这就是为什么isset()更快

$string = 'abcdefg';
var_dump($string[2]);
Output: string(1) “c”

$string = 'abcdefg';
if (isset($string[7])){
     echo $string[7].' found!';
  }else{
     echo 'No character found at position 7!';
}
Run Code Online (Sandbox Code Playgroud)

这比使用strlen()更快,因为"...调用函数比使用语言结构更昂贵." http://www.phpreferencebook.com/tips/use-isset-instead-of-strlen/

EDIT3:我总是被教导对mirco-optimization感兴趣.可能是因为我在计算机上的资源很少的时候被教过.我对这个可能并不重要的观点持开放态度,在答案中有一些好的论据反对它.我已经开始探索这个问题... /sf/ask/488824591/

Roe*_*oel 52

好的,所以我运行测试,因为我几乎不相信isset()方法更快,但是是的,并且相当如此.isset()方法一直快6倍左右.

我尝试过各种大小的字符串并运行不同的迭代次数; 比率保持不变,顺便说一下总运行长度(对于不同大小的字符串),因为isset()和strlen()都是O(1)(这有意义 - isset只需要在一个C数组,strlen()只返回为字符串保留的大小计数.

我在php源代码中查找了它,我想我大致理解为什么.isset(),因为它不是一个函数而是一个语言结构,在Zend VM中有自己的操作码.因此,不需要在函数表中查找它,它可以进行更专业的参数解析.对于那些感兴趣的人,代码在zend_builtin_functions.c中用于strlen()和zend_compile.c用于isset().

为了将其与原始问题联系起来,从技术角度来看,我没有看到任何与isset()方法有关的问题; 但对于那些不熟悉习语的人来说,更难以阅读.此外,isset()方法将在时间上保持不变,而strlen()方法在改变构建到PHP中的函数量时将是O(n).意思是,如果你构建PHP并在许多函数中静态编译,所有函数调用(包括strlen())都会变慢; 但是isset()将是不变的.然而,这种差异在实践中可以忽略不计; 我也不知道维护了多少个函数指针表,因此如果用户定义的函数也有影响.我似乎记得他们在不同的桌子上因此与这种情况无关,但是自从我上次真正使用它以来已经有一段时间了.

对于其余的我没有看到isset()方法的任何缺点.我不知道其他方法来获得字符串的长度,当不考虑有目的的复杂的,如爆炸+计数和类似的东西.

最后,我还测试了上面关于将isset()包装到函数中的建议.这比strlen()方法慢,因为你需要另一个函数调用,因此需要另一个哈希表查找.额外参数的开销(对于要检查的大小)可以忽略不计; 当没有通过引用传递时复制字符串也是如此.

  • +1用于深入解释 - 虽然我保持优化在大多数情况下仍然没有意义,并且使用`strlen`从维护的角度来看是优越的. (3认同)

Pek*_*ica 19

任何速度差异都绝对没有影响.最多只需几毫秒.

使用对你和其他任何从事代码工作的人来说最好的风格 - 我个人会强烈投票给第二个例子,因为与第一个例子不同,它使得意图(检查字符串的长度)绝对清楚.

  • @scube做数学.根据下面的测试,使用`isset()`将为100,000次迭代节省0.3秒.因此,在您的新闻通讯系统中,这种"优化"总共会产生*0.15秒*,而实际发送邮件的过程将是每个收件人*的一百倍*. (9认同)
  • 我总是喜欢清晰/可读性而不是这些小的速度提升; 因此,我总是选择strlen(),无论它是否慢了几毫秒.如果像这样的性能差异是至关重要的,PHP是您的任务的错误语言. (7认同)
  • 您为什么告诉它没有后果?在具有许多(循环)字符串长度比较的任务中,我肯定会使用多数民众赞成的速度! (2认同)
  • @scube向我展示了一个真实的情况,你需要在PHP脚本中进行这种微优化. (2认同)

Bor*_*kov 12

您的代码不完整.

在这里,我为你修好了:

if(isset($string[255])) {
    // something taking 1 millisecond
}
Run Code Online (Sandbox Code Playgroud)

VS

if(strlen($string) > 255) {
    // something taking 1 millisecond
}
Run Code Online (Sandbox Code Playgroud)

现在你没有一个空循环,而是一个现实循环.让我们考虑做一些事情需要1毫秒.

现代CPU可以在1毫秒内完成很多事情 - 这是给定的.但是随机硬盘访问或数据库请求之类的事情需要几毫秒 - 这也是一个现实的场景.

现在让我们再次计算时间:

realistic routine + strlen() over 1000000 iterations 1007.5193998813629
realistic routine + isset() over 1000000 iterations 1000.29940009117126
Run Code Online (Sandbox Code Playgroud)

看到不同?


Nik*_*kiC 5

首先,我想指出Artefacto 的答案,解释为什么函数调用会比语言结构带来开销。

其次,我想让您意识到 XDebug 会大大降低函数调用的性能,因此如果您正在运行 XDebug,您可能会得到令人费解的数字。参考(问题的第二部分)。因此,在生产中(您希望没有安装 XDebug),差异甚至更小。它从 6 倍下降到 2 倍。

第三,您应该知道,即使存在可测量的差异,这种差异也仅在此代码在具有数百万次迭代的紧密循环中运行时才会出现。在普通的 Web 应用程序中,差异是不可测量的,它会在差异的噪音中消失。

第四,请注意,现在开发时间比服务器负载昂贵得多。开发人员即使只多花半秒时间来理解 isset 代码的作用,也比节省 CPU 负载要昂贵得多。此外,通过应用实际产生影响的优化(如缓存),可以更好地节省服务器负载。