说起php的执行时间,相信每一个phper都遇到过这方面的问题,特别是在CGI模式下,一般我们都会通过修改max_execution_time或者在代码开头添加set_time_limit(0)来解决问题,但下面这个场景大家可能也曾经遇到过:

我们先将php.ini的执行时间设置为60S

max_execution_time = 60

再在代码的开头设置执行时间为60S,让两者统一

然后运行sleep让程序模拟运行20S:

set_time_limit(60);

sleep(20);

echo 1;

会发现程序在执行到第16S的时候就报出了502 Bad Gateway

说好的可以执行60S呢?江湖规矩报错先翻看日志,查看php-fpm.log,可以发现有这么一段信息

[06-Dec-2019 12:44:13] WARNING: [pool www] child 19910, script '/home/wwwroot/public/index.php' (request: "GET /index.php") execution timed out (16.120721 sec), terminating

[06-Dec-2019 12:44:13] WARNING: [pool www] child 19910 exited on signal 15 (SIGTERM) after 2573.443300 seconds from start

[06-Dec-2019 12:44:13] NOTICE: [pool www] child 21861 started

这三行日志分别告诉了我们三个信息

1.子进程19910的执行时间超过了16S被终结了

2.子进程19910在启动了2573.44S后被关闭了

3.子进程19910在关闭后的同一秒子进程child 21861被fork出来开始运行

也就是说,PHP-CGI在执行的过程中,除去我们之前已经设置好的两个参数,应该还有另外一个参数限制了这个进程的执行时间,打开php目录下的php-fpm.conf看看有无异常

...

pm.min_spare_servers = 16

pm.max_spare_servers = 60

request_terminate_timeout = 15

request_slowlog_timeout = 0

slowlog = var/log/slow.log

...

可以看到有一个参数request_terminate_timeout = 15 和我们的超时阈值非常接近,翻看注释找到关于这个参数的解释:

; The timeout for serving a single request after which the worker process will

; be killed. This option should be used when the 'max_execution_time' ini option

; does not stop script execution for some reason. A value of '0' means 'off'.

大概的意思是这个参数的设置是当max_execution_time启用时,为了防止php子进程因为某些原因无法停止运行而设置的一个保护措施,当然这个保护措施比较简单粗暴,就是直接kill超时的子进程,然后直接fork一个新的

结合解释,我们就很好理解前面日志中出现的三条信息了:因为执行时间超过了max_execution_time设置的阈值,子进程19910被直接kill了,然后又生成了一个新的子进程21861

于是我们将php-fpm.conf中的request_terminate_timeout改为30,重启php,再次执行之前的代码,不再报502了

看到这里,可能会有小伙伴会说,PHP的执行执行时间影响的参数有点多,真的记不住应该改那个才真正的有效,我们不妨从php运行的架构来梳理一下,不太清楚php运行架构的小伙伴可以看看我之前写的《浅析PHP-FPM、CGI、Fast CGI的关系》

PHP-FPM的程序架构是由一个master进程来进行管理一个PHP-CGI的子进程池,当一个请求由master进程转发到worker时,master进程便会开始计时,当超过设定的执行时间时master进程,便会直接kill掉超时的worker进程(程序的世界也不好混),而我们设置max_execution_time设置的时间是对于workder进程而言的,所以无论单个worker进程的执行时间设置多少,都不得超过fpm中的request_terminate_timeout,否则一律kill

文末,再补充两条在翻看手册时翻到的知识点:

在代码中使用set_time_limit()会从零开始重新启动超时计数器

换句话说,如果超时默认是30秒,在脚本运行了了25秒时调用 set_time_limit(20),那么,脚本在超时之前可运行总时间为45秒。

这个相对简单,就不上测试代码了,大家有空可以验证一下

set_time_limit()函数和配置指令max_execution_time只影响脚本本身执行的时间

其他发生在诸如使用system()的系统调用,流操作,数据库操作等的脚本执行的最大时间不包括其中。也就是说,比如sleep或者file_get_contents等操作消耗的时间是不会计入max_execution_time的超时时间中的

所以其实我前文写的代码即使把sleep设置为999也不会报执行超时的错误

,用代码验证下:

set_time_limit(10);

sleep(20);

可以发现程序确实没有报超时的错误,接着我们再编写一段代码,让php执行非系统调用和数据流等操作的耗时任务

set_time_limit(10); //将计数器清零,允许执行时间为10S

sleep(10);

$json[] = str_repeat("123456789,",10000); //生成一个内容量较大的数组

$count = 1000000;

//循环执行1000000次数据,json_encode和json_decode在对于长字符串的转化效率不高,所以比较耗时

while ($count--){

$string = json_encode($json);

json_decode($string,true);

}

结果如上图,程序一共执行了20S,其中有10S是在sleep也就是系统调用不算入执行超时时间,另外10s执行的是一段cpu密集型的操作,符合算入max_execution_time超时时间的要求,于是符合条件抛出错误

文末总结:有空可以多翻翻手册,每天都有新发现

php里面的耗时操作,PHP执行时间那点事相关推荐

  1. 在耗时操作结束之前 销毁tableView 如何让tableViewCell 销毁

    2019独角兽企业重金招聘Python工程师标准>>> 问题产生环境: 点击tableView的某一行,APP执行耗时操作,在耗时操作结束之前用户点击了返回按钮,tableView被 ...

  2. java耗时操作阻塞_springboot~高并发下耗时操作的实现

    高并发下的耗时操作 官方文档中说DeferredResult和Callable都是为了异步生成返回值提供基本的支持.简单来说就是一个请求进来,如果你使用了DeferredResult或者Callabl ...

  3. 模拟耗时操作_在集成测试中模拟耗时的动作

    模拟耗时操作 最近在我的一个项目中,我遇到一种情况,需要为该应用程序创建集成测试. 这不是很奇怪,不是吗? 有趣的是,应用程序的逻辑涉及一些并发问题,并且其中一个组件必须连接到外部服务,这将花费几秒钟 ...

  4. java耗时操作阻塞_spring boot高并发下耗时操作的实现方法

    高并发下的耗时操作 高并发下,就是请求在一个时间点比较多时,很多写的请求打过来时,你的服务器承受很大的压力,当你的一个请求处理时间长时,这些请求将会把你的服务器线程耗尽,即你的主线程池里的线程将不会再 ...

  5. 关于tornado的异步耗时操作假设

    tornado 如果遇到耗时的操作,可不可以这样 把耗时操作放在一个由 python进程池维护的 pool中, 用 webapi封装起来, 然后tornado 接收客户端请求后,遇到耗时操作就 与访问 ...

  6. android编程任务进度条,Android应用开发之AsyncTask 处理耗时操作和显示进度条

    在Android中实现异步任务机制有两种,Handler和AsyncTask.优缺点自己百度,推荐使用AsyncTask. private ProgressDialog dialog; //新建一个对 ...

  7. 【Android】Android主线程真的不让进行耗时操作吗?

    默认情况下,Android主线程(UI线程)不让进行网络请求,否则会抛出NetworkOnMainThreadException. 但是主线程还可以让程序员进行其它类型的耗时操作,比如读写磁盘数据.遍 ...

  8. 【opencv4.3.0教程】08之图像掩膜(Mask)操作与执行时间

    目录 一.前言 二.温故知新--像素基本操作 1.获取像素指针 2.像素范围处理 3.读写像素 三.图像掩膜操作 1.怎么理解掩膜Mask 2.掩膜实现 3.API-filter2D 四.执行时间 一 ...

  9. springboot高并发下耗时操作的实现,我先收藏为敬

    什么是 Arthas? Arthas 是一款开源在线诊断工具,采用命令行交互模式,支持 web 端在线诊断,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断.这是一款开源一年多 G ...

最新文章

  1. console线驱动安装_centos7安装docker
  2. 如何创建一张表mysql_如何创建一张规范的MySQL表
  3. java命令详解 java -D
  4. Modbus寄存器地址规则
  5. Oracle ROLLUP和CUBE 用法
  6. 新年新计划-2021年
  7. .Net 转战 Android 4.4 日常笔记(1)--工具及环境搭建
  8. 面向对象chapter10
  9. 只会java_只会码代码的你和Java工程师之间的差距有大?
  10. hive 直接访问mysql_hive 直接插入mysql
  11. 在Mac OS X 通过抓包、“第三方下载工具”加速下载、安装APP或系统
  12. CSS3背景渐变。。。
  13. Redis系列——Redis实战
  14. 360Lib整体介绍
  15. html涟漪效果,涟漪效果.html
  16. 高考必胜|东方星书法祝全体考生旗开得胜,金榜题名
  17. 2021-08-13 TM32F103 SRAM 内存扩展管理
  18. 医疗器械行业数据分析必备软件--全球可查
  19. 总结了一下小半辈子发现三点:
  20. 2021年终总结 万千热爱 初心未改 行至天光

热门文章

  1. java 变量共享_java对象,共享变量
  2. 三十七、数据泛化(面向属性的归纳)
  3. 一个悄然成为世界最流行的操作系统诞生!
  4. 维度爆炸?Python实现数据压缩竟如此简单!
  5. python程序一定要有主函数_Python 没有main函数的原因
  6. bootstrap mysql分页_bootstrap分页
  7. PyTorch基础-模型的保存和加载-09
  8. HTML游戏黑屏,网页游戏黑屏:游戏进不去解决方案
  9. springboot+shiro+redis项目整合
  10. 秒杀多线程第六篇 经典线程同步 事件Event