简体   繁体   English

PHP 7-assert(string)有时非常慢

[英]PHP 7 - assert(string) is sometimes very slow

I recently copied a site to a new server which is running PHP 7. The code is heavily reliant on assert() calls. 我最近将一个站点复制到了运行PHP 7的新服务器上。该代码在很大程度上依赖assert()调用。 In order to get assertions running on the new server, we have to set zend.assertions to 1. Assertions work now, but about half the time, certain pages will load extremely slowly (60+ seconds). 为了使断言在新服务器上运行,我们必须将zend.assertions设置为1。断言现在可以工作,但是大约有一半的时间,某些页面将非常缓慢地加载(超过60秒)。

I have debugging functions which let me see how long each block of code takes. 我有调试功能,可让我看到每个代码块需要花费多长时间。 They show me that sometimes calling assert() takes less than a millisecond, but other times it costs about 60 milliseconds. 他们告诉我,有时调用assert()的时间少于一毫秒,而其他时间则花费约60毫秒。

I found this out when I added the following [pseudo-code] to an area of my code where I'd observed slowdowns: 当我在观察到速度变慢的代码区域中添加以下[伪代码]时,便发现了这一点:

  1. output the time 输出时间
  2. call assert(true) 100 times 调用assert(true)100次
  3. output the time 输出时间
  4. call assert('true') 100 times 调用assert('true')100次
  5. output the time 输出时间

This lets me see how costly the "assert()" calls are, both with expressions as parameters [the assert(true) call] and also with string-expressions as parameters [the assert('true') call]. 这让我看到以表达式为参数[assert(true)调用]和以字符串表达式为参数[assert('true')调用]的“ assert()”调用的代价如何。

Sometimes when I refresh the page, both loops take less than 1 millisecond total. 有时,当我刷新页面时,两个循环总共花费不到1毫秒。

Other times, however, the first few passes through those loops might be fast, but then suddenly the assert('true') loop takes more than 6 seconds, which means each assert('true') call takes about 60 milliseconds. 然而,有时其他情况下,通过这些循环的前几次可能很快,但是随后assert('true')循环突然花费了6秒钟以上,这意味着每个assert('true')调用大约花费了60毫秒。 The assert(true) calls are still fast, however. assert(true)调用仍然很快。

This implies that sometimes when we call assert() with a string parameter, the evaluation of that string is extremely slow. 这意味着有时当我们使用字符串参数调用assert()时,对该字符串的求值非常慢。

It's erratic, though. 但是,这很不稳定。 Like I said, half the time I refresh the page, assert('true') is fast the whole time... but other times assert('true') stats costing about 60 milliseconds for each call. 就像我说的那样,刷新页面有一半时间,assert('true')一直很快速...但是其他时候,每次调用的assert('true')统计信息耗时约60毫秒。

When zend.assertions is set to -1, the assert('true') calls are apparently never evaluated, and there is never any slowness. 当zend.assertions设置为-1时,assert('true')调用显然不会被评估,并且永远不会变慢。

I have never encountered this sort of slowness before, and I've used asserts on several servers in the past. 我以前从未遇到过这种缓慢的情况,过去我在多台服务器上使用了assert。 Never with PHP 7, though. 但是永远不要使用PHP 7。

A quick "solution" might be to stop using assertions, or stop passing strings as parameters to the assert() function.... But I have hundreds or thousands of functions, all of which use assert() with string parameters! 一个快速的“解决方案”可能是停止使用断言,或者停止将字符串作为参数传递给assert()函数。...但是我有成百上千个函数,所有这些函数都将assert()与字符串参数一起使用! I got in the habit of using assert() with strings long ago, when it was considered best practice (so that you could log or email the failed expressions when they occur in a production environment). 很久以前,我就习惯将assert()与字符串一起使用,这被认为是最佳做法(这样,当在生产环境中出现失败的表达式时,您就可以记录或通过电子邮件发送它们)。

So, what I need is to find a way to prevent PHP 7 from sporadically causing assert(string) to cost 60 milliseconds. 因此,我需要找到一种方法来防止PHP 7偶尔导致assert(string)花费60毫秒。

Any idea how to fix this? 任何想法如何解决这个问题?

Thanks! 谢谢!

A system admin/PHP export was able to find the problem. 系统管理员/ PHP导出能够找到问题。 It's a compatibility bug between the opcache module and assertions. 这是opcache模块和断言之间的兼容性错误。

Basically, in PHP 7.0 (at least our version), if opcache is enabled (as it is by default in PHP) and zend.assertions=1 then over time the opcache logic and the zend assertion logic start interfering with each other, resulting in very slow execution of assert(string) calls. 基本上,在PHP 7.0(至少是我们的版本)中,如果启用了opcache(PHP默认情况下) 并且 zend.assertions = 1,则随着时间的推移,opcache逻辑和zend断言逻辑开始相互干扰,从而导致assert(string)调用的执行速度非常慢。

So, it's a very weird bug, and the only people who would encounter it are those of us who are using PHP 7.0 with lots of assert(string) calls (and opcache left in its enabled state). 因此,这是一个非常奇怪的错误,唯一遇到此错误的人是使用PHP 7.0且有很多assert(string)调用(并且opcache处于启用状态的人)的人。

The quick fix is to disable opcache, either via php.ini or by calling opcache_reset() at the start of the PHP. 快速解决方案是通过php.ini或在PHP开头调用opcache_reset()来禁用opcache。

I have test both fixes and they work. 我已经测试了两个修复程序,并且它们都能正常工作。 I prefer the php.ini fix because the opcache_reset() does not work on all installations of PHP; 我更喜欢php.ini修复程序,因为opcache_reset()不适用于所有的PHP安装。 I got an undefined function error when I tried calling that function on another server. 尝试在另一台服务器上调用该函数时出现未定义的函数错误。

Of course, the best long-term solution is for someone to fix the opcache and/or assertion libraries so that they don't conflict. 当然,最好的长期解决方案是让某人修复opcache和/或断言库,以免它们冲突。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM