max_execution_time对file_get_contents()、mysqli_query()无效,因其仅统计cpu执行时间,不计i/o阻塞(如recv、read系统调用)、sleep及网络等待;真实超时需依赖curl/pdo自身超时设置及web服务器层配置。

max_execution_time 为什么对 file_get_contents()、mysqli_query() 不起作用
max_execution_time 只统计 PHP 脚本的「用户态 CPU 执行时间」,不包含系统调用阻塞时长。当你用 file_get_contents() 请求一个响应慢的 API,或用 mysqli_query() 等待锁表/网络延迟,PHP 内部会进入 read()、recv() 等系统调用并挂起——此时计时器完全停止。
这意味着:即使你设了 max_execution_time = 30,但下游服务卡住 2 分钟,PHP 进程仍会等满 2 分钟才返回(如果没被 Web 服务器先杀掉)。
- 它不控制 I/O 等待、DNS 解析、SSL 握手、数据库锁等待
-
sleep()、usleep()也不计入 —— 它们本质是让出 CPU,不是执行 - 真正生效的场景只有密集计算(如循环 hash、递归解析大 XML)
怎么确认脚本到底卡在哪儿:用 strace 抓系统调用
盲目调大 max_execution_time 没用,得先定位真实阻塞点。Linux 下最直接的方式是用 strace 观察进程在等什么:
在终端中执行:
strace -p $(pgrep -f "php your_script.php" | head -1) -e trace=network,io -T 2>&1 | grep -E "(recv|send|read|write|connect)"
你会看到类似这样的输出:
recvfrom(3, ..., MSG_WAITALL) = -1 EAGAIN (Resource temporarily unavailable)或长时间无输出——说明卡在某个
recvfrom 上。- 只抓
network和io类系统调用,避免噪音 -
-T显示每次调用耗时,一眼看出哪次卡了 5 秒以上 - 若进程已退出,可改用
strace -f -o trace.log php your_script.php全量记录
curl 和 PDO 必须自己设超时,不能依赖 max_execution_time
所有显式发起外部交互的扩展,都提供独立超时参数,且它们优先级远高于 max_execution_time:
比如 curl:
$ch = curl_init();<br>curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 整个请求最大耗时<br>curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); // 连接阶段超时
比如 PDO(MySQL):
$pdo = new PDO($dsn, $user, $pass, [<br> PDO::ATTR_TIMEOUT => 5, // 连接超时(秒)<br>]);<br>// 查询超时需靠 MySQL 服务端设置 wait_timeout / interactive_timeout
-
CURLOPT_TIMEOUT是从发起请求到收到完整响应的总时限,含 DNS、连接、发送、接收 -
PDO::ATTR_TIMEOUT仅控制连接建立,不控制查询执行;查慢表必须配 MySQL 的max_execution_time(5.7+)或用SET STATEMENT max_execution_time=3000 FOR SELECT ... - 不设这些,哪怕
max_execution_time是 0,curl/PDO 也可能无限挂起
Web 服务器层超时比 PHP 更早触发,且无法被 set_time_limit() 绕过
你看到的 504 Gateway Timeout 或空白页,99% 是 Nginx/Apache/FPM 主动断开,和 PHP 自身无关:
Nginx 配置里:
fastcgi_read_timeout 60; # 从 FPM 收响应的最长等待时间Apache mod_php 下:
Timeout 60 # 整个请求生命周期上限PHP-FPM 配置里:
request_terminate_timeout = 30s # 比 max_execution_time 更狠,直接 kill 进程
-
set_time_limit(0)对request_terminate_timeout完全无效 - 修改
max_execution_time后必须同步调大对应 Web 层参数,否则白改 - FPM 模式下,
request_terminate_timeout默认是 0(不限),但很多托管环境会显式设为 30s —— 查php-fpm.conf或用php-fpm -tt验证
真正麻烦的不是调参,而是当多个层级各自设了不同超时,又没日志联动,问题发生时根本分不清是谁掐断了谁。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











