因为PHP的pcntl_signal信号处理器被延后到tick点触发,而declare(ticks=1)强制Zend引擎每执行一条可计时语句就检查未决信号,否则信号注册虽成功却永不执行。
为什么 signal 处理必须配 declare(ticks=1)
PHP 的
注册的信号处理器不会立即执行,而是被“延后”到下一个 tick 点触发。Zend 引擎默认不检查未决信号,
的作用就是强制它每执行一条可计时的低级语句(如赋值、函数调用、控制结构入口等)就检查一次是否有待处理信号。
没加这句,哪怕你
成功了,按 Ctrl+C 也完全没反应——不是注册失败,是根本没机会触发。
必须写在文件最开头,不能包裹在函数或条件块里
它只对当前文件生效;如果被
或
,不会影响父文件
不是所有语句都算“可计时”:
条件表达式、
的判断部分、函数参数列表里的表达式通常不触发 tick
ticks=1 和 ticks=1000 的实际差异在哪
数值只控制“检查频率”,不改变行为本质。
表示每条可计时语句后检查一次信号或 tick 函数;
则是累计执行约 1000 条后才检查一次。
对信号处理来说,
可能导致按下 Ctrl+C 后要等很久才响应——尤其当循环体里全是不可计时语句(比如一个空
)时,可能永远卡住。
立即学习
“
PHP免费学习笔记(深入)
”;
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
生产环境若用
做优雅退出,必须用
更适合做粗粒度性能采样,比如每千条语句记录一次内存使用,而非实时响应
数值不能是变量或常量:
会报错,只能写死数字
register_tick_function() 和信号共存时要注意什么
两者共享同一套 tick 机制。只要启用了
,每次 tick 不仅会调用
注册的函数,也会检查未决信号并分发给
处理器。
但顺序不保证:tick 函数和信号处理器谁先执行,取决于 Zend 内部调度,不能依赖先后关系。
不要在 tick 函数里做耗时操作(如 I/O、sleep),否则会拖慢信号响应
避免在 tick 函数和信号处理器中同时修改同一全局变量,没有锁保护
信号处理器内禁止调用非异步安全函数(如
、
、
相关),
是安全的,但
不是
常见错误现象:信号没触发,但 pcntl_signal 返回 true
这是最典型的误判场景。返回
只代表注册成功,并不代表运行时会被调用。典型表现是:
脚本一直在跑,Ctrl+C 没反应,
也没反应
加了
确认返回的是你的回调,但仍不执行
把
移到文件中间或包进函数后,问题复现
真正起作用的只有两件事:一是文件顶部存在有效的
,二是代码中持续有可计时语句被执行(比如循环里的赋值、函数调用)。纯空循环
在某些 PHP 版本下可能不触发 tick,建议至少加一句
或
。
pcntl_signaldeclare(ticks=1)pcntl_signal(SIGINT, $handler)declare(ticks=1)includerequireifforticks=1ticks=1000ticks=1000while(1);pcntl_signalticks=1ticks=1000declare(ticks=TICK_VALUE)declare(ticks=1)register_tick_function()pcntl_signalechoprint_rmallocpcntl_signal_dispatch()var_dumptruekill -SIGTERM $pidpcntl_signal_get_handler(SIGTERM)declare(ticks=1)declare(ticks=N)while(1){}$i++usleep(1)