PHP 与 pcntl_signal 的 "good" 设置是什么?

What's a "good" setting for PHP ticks with pcntl_signal?

我是 运行 一个带有信号处理程序的 PHP 守护程序,可以进行有序清理并在不停止的情况下重新配置:

declare(ticks = 5);
function sig_handler($signo)
{
    ...
}
pcntl_signal(SIGHUP, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
...

A tick is an event that occurs for every N low-level tickable statements executed by the parser within the declare block... Not all statements are tickable. Typically, condition expressions and argument expressions are not tickable.

如果我们声明 ticks = 1 那么信号将在执行 PHP 代码的大多数行之间进行检查,这看起来效率很低。所以,

(旁注:The formal specs 更不具体,因为这可能取决于解释器。)

以下是我的发现,我无法向您提供任何文档参考来证明我的陈述。但是,我通过阅读 PHP 的源代码(pcntl extension)了解了 PHP 解释器处理滴答和信号的方式。

  • If we set ticks = 5, does that mean we have a 4 in 5 chance the signal handler won't be called at all?

PHP 是一种解释型语言。 OS 不会调用您的 PHP 信号处理程序来处理信号。解释器用 OS 注册一个信号处理程序,并将它接收到的所有信号放入队列中。

OS 信号是异步的。解释器会在最合适的时间将信号分派给您定义的处理程序。这发生在低级可勾选语句之间。

declare(ticks = 5); 每 5 个可勾选语句使信号调度器 运行 一次。在两次呼叫调度员期间到达的信号不会丢失;它们被添加到队列中并在下一次调用时处理。

信号调度器的代码非常简单;使用 declare(ticks = 1).

不是很大的开销
  • How can I determine a consistent but efficient setting?

这取决于你的程序做什么。没有秘诀。尝试不同的设置,选择最适合您的设置。

  • What happens during blocking calls, like database queries? Is the signal thrown away or processed when it returns?

正如我上面所说,信号来了,并由解释器安装的信号处理程序异步处理。处理仅将信号放入队列中。当解释器(以及您的 PHP 代码)最合适的时候,它们会从队列中挑选出来并分派给您的代码。什么都没有丢失。

关于数据库,我(几年前)只用mysql检查过。我的代码早期使用了 pcntl_fork() to create worker processes and was processing SIGCHLD to keep track of workers activity. For mysterious reasons it was failing on the MySQL queries frequently with the message "connection lost" without any apparent reason. After extensive investigation and reading of a lot of documentation, I found out that the signals make the functions from the sleep() 系列 return,这使得 mysql 客户端库的代码认为连接丢失了。

解决方案非常简单。我在 运行 执行 MySQL 查询之前使用 pcntl_sigprocmask() 来阻止 SIGCHLD 信号,并在查询完成后立即取消阻止。我对其他信号不感兴趣。让他们来会导致进程终止;为什么要在程序即将退出时为失败的 MySQL 查询烦恼?

我不知道这些信号是否会影响 mysqliPDO 的操作,但我认为它们会影响。在我的案例中受影响的操作是 MySQL 客户端和服务器之间低级通信的一部分,深入 libmysql 而不是 PHP 扩展。

在您的情况下,您可能需要阻止 SIGHUP(这是通常发送给守护进程以使它们重新加载其配置的信号)。