我最近将一个站点复制到运行PHP 7的新服务器上。该代码严重依赖于assert()调用。为了在新服务器上运行断言,我们必须将zend.assertions设置为1.断言现在可以工作,但是大约一半的时间,某些页面加载速度非常慢(60+秒)。
我有调试功能,让我看看每个代码块需要多长时间。他们告诉我,有时调用assert()的时间不到一毫秒,但有时则花费大约60毫秒。
当我将以下[伪代码]添加到我的代码区域时,我发现了这一点,我观察到减速:
这让我看到"断言()"调用是,表达式作为参数[assert(true)调用],并且还使用字符串表达式作为参数[assert(' true')调用]。
有时当我刷新页面时,两个循环总共不到1毫秒。
然而,其他时候,通过这些循环的前几次传递可能很快,但突然断言('真正的')循环需要超过6秒,这意味着每个断言(' true')调用大约需要60毫秒。然而,断言(真实)调用仍然很快。
这意味着有时当我们用字符串参数调用assert()时,对该字符串的评估非常慢。
但是,它不稳定。就像我说的那样,我刷新页面的时间有一半,断言(' true')一直很快......但其他时间断言('真')统计耗时大约60毫秒每次通话。当zend.assertions设置为-1时,断言(' true')调用显然从未被评估过,并且永远不会有任何缓慢。
我之前从未遇到过这种缓慢的问题,过去我曾在多台服务器上使用断言。但不要使用PHP 7。
快速解决方案"可能是停止使用断言,或者停止将字符串作为参数传递给assert()函数....但我有数百或数千个函数,所有函数都使用带字符串参数的assert()!我习惯在很久以前使用assert()和字符串,当它被认为是最佳实践时(这样你就可以在生产环境中发生失败的表达式时记录或发送电子邮件)。
所以,我需要找到一种方法来阻止PHP 7偶尔导致断言(字符串)花费60毫秒。
知道如何解决这个问题吗?
谢谢!
答案 0 :(得分:0)
系统管理员/ PHP导出能够找到问题。这是opcache模块和断言之间的兼容性错误。
基本上,在PHP 7.0(至少是我们的版本)中,如果启用opcache(因为默认情况下在PHP中)和 zend.assertions = 1,那么随着时间的推移opcache逻辑和zend断言逻辑开始相互干扰,导致断言(字符串)调用执行速度非常慢。
所以,这是一个非常奇怪的错误,只有遇到它的人才是我们这些使用PHP 7.0并且有许多断言(字符串)调用(并且opcache处于启用状态)的人。
快速解决方法是通过php.ini或在PHP开头调用opcache_reset()来禁用opcache。
我测试了两个修复程序并且它们正常工作。我更喜欢php.ini修复,因为opcache_reset()不适用于所有PHP安装;当我尝试在另一台服务器上调用该函数时,我收到了一个未定义的函数错误。
当然,最好的长期解决方案是让某人修复opcache和/或断言库,以便它们不会发生冲突。