max_execution_time

原创
2020/05/14 11:24
阅读数 78

1,含义

max_execution_time 是 php.ini 文件中的配置,

;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;

; Maximum execution time of each script, in seconds
; http://php.net/max-execution-time
; Note: This directive is hardcoded to 0 for the CLI SAPI
; max_execution_time = 30

它是一种资源限制, 它规定了每一个PHP脚本的最大执行时间,这有助于防止写得不好的脚本占尽服务器资源。单位为秒,默认值是30秒。在命令行执行时,这个设置被硬编码成0,也就是对执行时间无限制。

最大执行时间不会影响系统调用和系统操作等。更多细节参见 set_time_limit()

 安全模式 下你不能通过 ini_set() 来修改此设置。 唯一的解决方法是关闭安全模式或者在 php.ini 中修改时间限制。

你的 web 服务器也可以有其他超时设置,也有可能中断 PHP 的执行。Nginx 有三个timeout指令,分别是 fastcgi_connect_timeout, fastcgi_send_timeout, fastcgi_read_timeout. Apache 有一个 Timeout 指令,IIS 有一个 CGI 超时功能。 他们默认都是 300 秒。更多具体信息参见你的 web 服务器的文档。

2. set_time_limit()

The set_time_limit() function and the configuration directive max_execution_time 
only affect the execution time of the script itself. Any time spent on activity 
that happens outside the execution of the script such as system calls using system(), the sleep() function, stream operations, database queries, etc. is not included 
when determining the maximum time that the script has been running. 
This is not true on Windows where the measured time is real.

set_time_limit() 方法和 php.ini 中的 max_execution_time 设置,只会影响PHP脚本本身的执行时间。任何在脚本执行之外的活动,例如 使用 system() 进行的系统调用,sleep()函数,流操作,数据库查询等,花费在这些活动上的时间,当在判断脚本执行的最大时间时,是不会计算到其中的。而在Windows中,这些活动会被计算到其中。

3,几种操作

3.1 系统调用

https://www.php.net/manual/zh/function.system.php

system(), exec(), passthru()

3.2 sleep()函数

https://www.php.net/manual/zh/function.sleep.php

sleep(), usleep(), time_nanosleep(), time_sleep_until()

3.3 流操作

https://www.php.net/manual/zh/intro.stream.php

https://www.php.net/manual/zh/internals2.ze1.streams.php

3.4 数据库查询

3.5 第三方接口调用 (自己试验的)

示例

nginx

fastcgi_send_timeout 10;

php-fpm

request_terminate_timeout = 10

php.ini

max_execution_time = 2

php

test.php

<?php

/**
 * 模拟post进行url请求
 * @param string $url
 * @param array $postData
 */
function request_post($url = '', $postData = array()) {

    $postUrl = $url;
    $ch = curl_init();//初始化curl
    //转义
//    $vars = http_build_query($postData, '', '&');

    curl_setopt($ch, CURLOPT_URL, $postUrl);//抓取指定网页
    curl_setopt($ch, CURLOPT_HEADER, 0);//设置header
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
//    curl_setopt($ch, CURLOPT_POST, 0);//post提交方式
//    curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);//参数
    $data = curl_exec($ch);//运行curl
    curl_close($ch);
    return $data;
}

/**
 * 测试
 * @param string $url
 */
function testAction() {
    $url = 'http://www.test.com/test2.php';
    $res = request_post($url);
    var_dump($res);
}

$s = microtime(true);
testAction();

$a = microtime(true);
$exTime = 1.50;
for($i=0;;$i++){
    $now = microtime(true);
    if( bcsub($now, $a, 2) > $exTime){
        break;
    }
}
$e = microtime(true);

$cost = bcsub($e, $s, 3);
echo 'cost:'.$cost.' seconds';

在这个脚本中,调用了 test2.php 文件,然后又自己执行了1.50秒

test2.php

<?php

$a = microtime(true);
$exTime = 3.10;
for($i=0;;$i++){
    $now = microtime(true);
    if( bcsub($now, $a, 2) > $exTime){
        break;
    }
}
echo 'hello world'.PHP_EOL;

在test2.php中,这里执行了至少3.10秒钟,

反馈

HTTP/1.1 200 OK
Server: nginx/1.17.4
Date: Wed, 13 May 2020 08:51:34 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive

string(0) ""
cost:3.519 seconds

可以看到,真正执行了3.519秒,而 max_execution_time 设置为 2秒,没有报500,而报200.

nginx access.log

127.0.0.1 - - [13/May/2020:20:00:08 +0800] "GET /test2.php HTTP/1.1" 500 5 "-" "-"
127.0.0.1 - - [13/May/2020:20:00:10 +0800] "GET /test.php HTTP/1.1" 200 42 "-" "curl/7.47.0"

nginx error.log

2020/05/13 20:00:08 [error] 9625#9625: *196 FastCGI sent in stderr: 
"PHP message: PHP Fatal error:  Maximum execution time of 2 seconds exceeded in /opt/wwwroot/test/test2.php on line 8" while reading response header from upstream, 
client: 127.0.0.1, server: www.test.com, request: "GET /test2.php HTTP/1.1", 
upstream: "fastcgi://unix:/run/php/php7.3-fpm.sock:", host: "www.test.com"

php-fpm access.log

- -  13/May/2020:20:00:06 +0800 "GET /test2.php" 500
- -  13/May/2020:20:00:06 +0800 "GET /test.php" 200

php-fpm log.slow

[13-May-2020 20:00:07]  [pool www] pid 40604
script_filename = /opt/wwwroot/test/test2.php
[0x00007fc65c81e0e0] bcsub() /opt/wwwroot/test/test2.php:8

[13-May-2020 20:00:07]  [pool www] pid 40637
script_filename = /opt/wwwroot/test/test.php
[0x00007fc65c81e230] curl_exec() /opt/wwwroot/test/test.php:24
[0x00007fc65c81e180] request_post() /opt/wwwroot/test/test.php:35
[0x00007fc65c81e110] testAction() /opt/wwwroot/test/test.php:41

php.ini error.log

[13-May-2020 20:00:07] WARNING: [pool www] child 40637, script '/opt/wwwroot/test/test.php' (request: "GET /test.php") executing too slow (1.084758 sec), logging
[13-May-2020 20:00:07] WARNING: [pool www] child 40604, script '/opt/wwwroot/test/test2.php' (request: "GET /test2.php") executing too slow (1.054616 sec), logging
[13-May-2020 20:00:07] NOTICE: child 40604 stopped for tracing
[13-May-2020 20:00:07] NOTICE: about to trace 40604
[13-May-2020 20:00:07] NOTICE: finished trace of 40604
[13-May-2020 20:00:07] NOTICE: child 40637 stopped for tracing
[13-May-2020 20:00:07] NOTICE: about to trace 40637
[13-May-2020 20:00:07] NOTICE: finished trace of 40637

可以看到,test2.php执行了3.10秒,超出了 2秒的max_exection_time,所以500了。而调用方test.php执行了 调用接口的 2秒 + 自己的1.5秒 ~= 3.5秒。

已超过了 2秒的max_exection_time,但是并没有返回500,而是200。由此可见,调用第三方接口所耗费的时间,也没有被记录到 max_exection_time 中。

 

4,猜测

以上四种,系统调用,Sleep(),流操作,外部API调用,都涉及到进程中 CPU的用户态和内核态、内存的用户空间和内核空间的切换,如文件的流操作,会在用户空间的IO缓冲区和内核空间的页缓存中进行读写切换,API调用,涉及到网络的数据读取,CPU的等待,所以,我猜测,max_execution_time只统计用户态的执行时间。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部