Performance of try-catch in php
在php 5中使用try-catch语句时需要考虑哪些性能影响?
我之前在网上看过一些关于这个主题的旧的,看似相互矛盾的信息。 我目前必须使用的很多框架都是在php 4上创建的,并且缺少php 5的许多细节。所以,我自己在使用php的try-catchs时没有多少经验。
需要考虑的一件事是,没有抛出异常的try块的成本与实际抛出和捕获异常的成本是一个不同的问题。
如果只在故障情况下抛出异常,那么您几乎肯定不关心性能,因为每次执行程序时都不会失败很多次。如果你在一个紧凑的循环中失败了(a.k.a:将你的头撞在砖墙上),你的应用程序可能比慢速更糟糕。所以不要担心抛出异常的成本,除非你以某种方式被迫将它们用于常规控制流程。
有人发布了一个答案,讨论分析引发异常的代码。我自己从来没有对它进行过测试,但我自信地预测,这将显示出一个更大的性能影响,而不仅仅是进入和退出try块而不抛出任何东西。
另一件需要考虑的事情是,在嵌套调用很多级别的情况下,在顶部进行单次尝试...捕获甚至可以更快地检查返回值并在每次调用时传播错误。
与那种情况相反,你发现你在自己的try ... catch块中包含每个调用,你的代码会变慢。而且丑陋。
我很无聊并描述了以下内容(我把时间码留下了):
1 2 3 4 5 6 7 8 9 10 | function no_except($a, $b) { $a += $b; return $a; } function except($a, $b) { try { $a += $b; } catch (Exception $e) {} return $a; } |
使用两个不同的循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | echo 'no except with no surrounding try'; for ($i = 0; $i < NUM_TESTS; ++$i) { no_except(5, 7); } echo 'no except with surrounding try'; for ($i = 0; $i < NUM_TESTS; ++$i) { try { no_except(5, 7); } catch (Exception $e) {} } echo 'except with no surrounding try'; for ($i = 0; $i < NUM_TESTS; ++$i) { except(5, 7); } echo 'except with surrounding try'; for ($i = 0; $i < NUM_TESTS; ++$i) { try { except(5, 7); } catch (Exception $e) {} } |
在我的WinXP盒子上运行1000000运行apache和PHP 5.2.6:
1 2 3 4 | no except with no surrounding try = 3.3296 no except with surrounding try = 3.4246 except with no surrounding try = 3.2548 except with surrounding try = 3.2913 |
这些结果是一致的,无论测试的顺序如何,都保持相似的比例。
结论:添加代码来处理罕见的异常并不比忽略异常的代码慢。
Try-catch块不是性能问题 - 真正的性能瓶颈来自创建异常对象。
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | function shuffle_assoc($array) { $keys = array_keys($array); shuffle($keys); return array_merge(array_flip($keys), $array); } $c_e = new Exception('n'); function no_try($a, $b) { $a = new stdclass; return $a; } function no_except($a, $b) { try { $a = new Exception('k'); } catch (Exception $e) { return $a + $b; } return $a; } function except($a, $b) { try { throw new Exception('k'); } catch (Exception $e) { return $a + $b; } return $a; } function constant_except($a, $b) { global $c_e; try { throw $c_e; } catch (Exception $e) { return $a + $b; } return $a; } $tests = array( 'no try with no surrounding try'=>function() { no_try(5, 7); }, 'no try with surrounding try'=>function() { try { no_try(5, 7); } catch (Exception $e) {} }, 'no except with no surrounding try'=>function() { no_except(5, 7); }, 'no except with surrounding try'=>function() { try { no_except(5, 7); } catch (Exception $e) {} }, 'except with no surrounding try'=>function() { except(5, 7); }, 'except with surrounding try'=>function() { try { except(5, 7); } catch (Exception $e) {} }, 'constant except with no surrounding try'=>function() { constant_except(5, 7); }, 'constant except with surrounding try'=>function() { try { constant_except(5, 7); } catch (Exception $e) {} }, ); $tests = shuffle_assoc($tests); foreach($tests as $k=>$f) { echo $k; $start = microtime(true); for ($i = 0; $i < 1000000; ++$i) { $f(); } echo ' = '.number_format((microtime(true) - $start), 4)." "; } |
结果:
1 2 3 4 5 6 7 8 | no try with no surrounding try = 0.5130 no try with surrounding try = 0.5665 no except with no surrounding try = 3.6469 no except with surrounding try = 3.6979 except with no surrounding try = 3.8729 except with surrounding try = 3.8978 constant except with no surrounding try = 0.5741 constant except with surrounding try = 0.6234 |
通常,使用异常来防止意外故障,并在代码中使用错误检查来防止作为正常程序状态一部分的故障。为了显示:
在数据库中找不到记录 - 有效状态,您应该检查查询结果并正确地向用户发送消息。
尝试获取记录时出现SQL错误 - 意外故障,记录可能存在也可能不存在,但是您有程序错误 - 这是异常的好地方 - 错误日志中的日志错误,向管理员发送电子邮件堆栈跟踪,以及显示向用户发出礼貌的错误消息,告诉他出现了问题并且您正在处理它。
例外是昂贵的,但除非您使用它们处理整个程序流程,否则任何性能差异都不应该是人类明显的。
我在Google上没有找到关于Try / Catch性能的任何内容,但是使用循环抛出错误而不是IF语句的简单测试在5000循环中产生329ms vs 6ms。
很抱歉发布了一条非常旧的消息,但我阅读了这些评论,我有点不同意,使用简单的代码片段可能会有所不同,或者在Try / Catch用于非特定代码部分的地方可能会忽略不计总是可以预测,但我也相信(未经测试)这简单:
比...更快
1 2 3 4 5 6 | try{ foreach($var as $k=>$v){ $var[$k] = $v+1; } }catch(Exception($e)){ } |
我也相信(未经测试)a:
1 2 3 4 5 6 7 8 9 10 11 12 | <?php //beginning code try{ //some more code foreach($var as $k=>$v){ $var[$k] = $v+1; } //more code }catch(Exception($e)){ } //output everything ?> |
比代码中有额外的IF更昂贵
这是一个非常好的问题!
我已经测试了很多次,从未看到任何性能问题;-) 10年前在C ++中确实如此,但我认为今天它们已经改进了很多,因为它非常有用和清洁。
但我仍然害怕用它来包围我的第一个切入点:
1 | try {Controller::run();}catch(...) |
我没有测试大量的函数调用和大包含....有没有人已经完全测试它了?
一般来说,它们很贵,在PHP中也不值得。
由于它是一种经过检查的表达式语言,因此必须捕获任何引发异常的内容。
在处理不抛出的遗留代码和新代码时,它只会导致混淆。
祝好运!