什么"好"用pcntl_signal设置PHP滴答?

时间:2016-04-25 16:24:52

标签: php daemon pcntl

我正在运行一个带有信号处理程序的PHP守护程序来进行有序清理并重新配置而不停止:

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

A tick是由声明块中的解析器执行的每N个低级别可勾选语句发生的事件...并非所有语句都是可勾选的。通常,条件表达式和参数表达式不可勾选。

如果我们声明ticks = 1,那么将在执行PHP代码的大多数行之间检查信号,这似乎是低效的。所以,

  • 如果我们声明ticks = 5,这是否意味着我们有四分之五的机会信号处理程序根本不会被调用?
  • 如何确定一致但有效的设置?
  • 在阻止调用期间会发生什么,例如数据库查询?信号在返回时是丢弃还是被处理?

(旁注:The formal specs甚至更不具体,因为这可能是依赖于解释器的。)

1 个答案:

答案 0 :(得分:5)

以下是我的调查结果,我无法提供任何文件证明我的陈述。但是,我通过阅读PHP的源代码(pcntl extension)了解了PHP解释器处理滴答和信号的方式。

  
      
  • 如果我们设置ticks = 5,这是否意味着我们有四分之五的机会信号处理程序根本不会被调用?
  •   

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

OS信号异步。解释器将信号发送给您定义的处理程序,当它处于最合适的时间时。这发生在低级别可勾选语句之间。

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

信号调度员的代码很轻;使用declare(ticks = 1)并不是一个很大的开销。

  
      
  • 如何确定一致但有效的设置?
  •   

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

  
      
  • 在阻止调用期间会发生什么,例如数据库查询?信号在返回时是丢弃还是被处理?
  •   

如上所述,信号由解释器安装的信号处理程序异步处理。处理仅将信号放入队列中。它们是从队列中挑选出来的,当它是解释器最合适的时刻(以及您的PHP代码)时,它们将被分派到您的代码中。什么都不会丢失。

关于数据库,我只用mysql检查了(几年前)。我的代码使用pcntl_fork()来创建工作进程,并正在处理SIGCHLD以跟踪工作人员的活动。出于神秘的原因,它经常在MySQL查询失败时显示消息"连接丢失"没有任何明显的理由。在经过大量调查和阅读大量文档之后,我发现信号使得sleep()系列中的函数提前返回,这使得mysql客户端库的代码认为连接丢失了。

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

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

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