PHP进程信号如何处理

后端开发   发布日期:2025年02月16日   浏览次数:205

这篇文章主要介绍“PHP进程信号如何处理”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“PHP进程信号如何处理”文章能帮助大家解决问题。

declare结构用来设定一段代码的执行指令。declare的语法和其它流程控制结构相似

  1. declare (directive)
    statement

directive部分允许设定declare代码段的行为。目前只认识两个指令:ticks和encoding。declare代码段中的 statement部分将被执行――怎样执行以及执行中有什么副作用出现取决于directive中设定的指令

Ticks

Tick(时钟周期)是一个在declare代码段中解释器每执行N条可计时的低级语句就会发生的事件N的值是在declare 中的directive部分用ticks=N来指定的。不是所有语句都可计时。通常条件表达式参数表达式都不可计时。在每个tick中出现的事件是由register_tick_function()来指定的,注意每个 tick 中可以出现多个事件 更详细的内容。

  1. <?php
    declare(ticks=1);//每执行一条时,触发register_tick_function()注册的函数
    $a=1;//在注册之前,不算
    function test(){//定义一个函数
    echo "执行
  2. ";
    }
    register_tick_function('test');//该条注册函数会被当成低级语句被执行
    for($i=0;$i<=2;$i++){//for算一条低级语句
    $i=$i;//赋值算一条
    }
    输出:六个“执行”

前边我们知道我们可以通过declare(ticks=1)和pcntl_signal组合的方式监听信号,即每一条PHP低级语句,就会检查一次当前进程是否有未处理的信号,这其实是十分耗性能的。

pcntl_signal的实现原理是,触发信号后先将信号加入一个队列中。然后在PHP的ticks回调函数中不断检查是否有信号,如果有信号就执行PHP中指定的回调函数,如果没有则跳出函数。

  1. PHP_MINIT_FUNCTION(pcntl)
    {
    php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
    php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
    php_add_tick_function(pcntl_signal_dispatch TSRMLS_CC);

    return SUCCESS;
    }

在PHP5.3之后,有了pcntl_signal_dispatch函数。这个时候将不在需要declare,只需要在循环中增加该函数,就可以调用信号通过了:

  1. <?php
    echo getmypid();//获取当前进程id
    pcntl_signal(SIGUSR1,function(){
    echo "触发信号用户自定义信号1";
    });
    while(1){
    pcntl_signal_dispatch();
    sleep(1);//死循环运行低级语句
    }

大家都知道PHP的ticks=1表示每执行1行PHP代码就回调此函数。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。如果一个服务器程序1秒中接收1000次请求,平均每个请求要执行1000行PHP代码。那么PHP的pcntl_signal,就带来了额外的 1000 * 1000,也就是100万次空的函数调用。这样会浪费大量的CPU资源。比较好的做法是去掉ticks,转而使用pcntl_signal_dispatch,在代码循环中自行处理信号。 pcntl_signal_dispatch 函数的实现:

  1. void pcntl_signal_dispatch()
    {
    //.... 这里略去一部分代码,queue即是信号队列
    while (queue) {
    if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
    ZVAL_NULL(&retval);
    ZVAL_LONG(&param, queue->signo);

    /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
    /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
    call_user_function(EG(function_table), NULL, handle, &retval, 1, &param TSRMLS_CC);
    zval_ptr_dtor(&param);
    zval_ptr_dtor(&retval);
    }
    next = queue->next;
    queue->next = PCNTL_G(spares);
    PCNTL_G(spares) = queue;
    queue = next;
    }
    }

但是上边这种,也有个恶心的地方就是,它得放在死循环中。PHP7.1之后出来了一个完成异步的信号接收并处理的函数: pcntl_async_signals

  1. <?php
    //a.php
    echo getmypid();
    pcntl_async_signals(true);//开启异步监听信号
    pcntl_signal(SIGUSR1,function(){
    echo "触发信号";
    posix_kill(getmypid(),SIGSTOP);
    });
    posix_kill(getmypid(),SIGSTOP);//给进程发送暂停信号

    //b.php
    posix_kill(文件1进程, SIGCONT);//给进程发送继续信号
    posix_kill(文件1进程, SIGUSR1);//给进程发送user1信号

通过pcntl_async_signals方法,就不用再写死循环了。

监听信号的包:

  1. https://github.com/Rain-Life/monitorSignal

以上就是PHP进程信号如何处理的详细内容,更多关于PHP进程信号如何处理的资料请关注九品源码其它相关文章!