Home  >  Article  >  Backend Development  >  The timer in the swoole server is inaccurate and jittering. Please answer.

The timer in the swoole server is inaccurate and jittering. Please answer.

WBOY
WBOYOriginal
2016-09-02 08:57:051185browse

The log printed by the timer shows jitter, as follows:
timer: ##23496 ##2016-09-01 19:23:24
timer: ##23496 ##2016-09-01 19:23:25
timer: ##23496 ##2016-09-01 19:23:27
timer: ##23496 ##2016-09-01 19:23:27
timer: ##23496 ##2016-09-01 19 :23:28
timer: ##23496 ##2016-09-01 19:23:29
timer: ##23496 ##2016-09-01 19:23:30
timer: ##23496 ##2016- 09-01 19:23:31
timer: ##23496 ##2016-09-01 19:23:33
timer: ##23496 ##2016-09-01 19:23:33
timer: ##23496 ##2016-09-01 19:23:36
timer: ##23496 ##2016-09-01 19:23:37
timer: ##23496 ##2016-09-01 19:23:39
timer : ##23496 ##2016-09-01 19:23:39
timer: ##23496 ##2016-09-01 19:23:40
timer: ##23496 ##2016-09-01 19:23 :41
timer: ##23496 ##2016-09-01 19:23:42
timer: ##23496 ##2016-09-01 19:23:43
timer: ##23496 ##2016-09- 01 19:23:45

Is there a problem with the process signal registration in timer? Or is there a problem with using signal and server together?
The code is as follows:

<code><?php
class box{
    static $list = array();

    static function processDo()
    {
        $echo = 'timer: ##'. posix_getpid() . ' ##'. date( 'Y-m-d H:i:s').PHP_EOL;
        file_put_contents( '/tmp/xx.log' , $echo , FILE_APPEND );

        $process = new swoole_process( function( swoole_process $worker ){
            swoole_set_process_name( 'lau_php_process' . posix_getpid() );
            exec( 'php -i' , $output , $status );
            echo 'process:' . posix_getpid() . ':: exec.status' . $status . PHP_EOL;
            sleep(5);
            $worker->exit(1);
        });
        if (!($pid = $process->start())) {
        }
        box::$list[$pid] = array(
            "start" => microtime(true),
            "process" =>$process,
        );
    }

    static function registerSingal()
    {
        swoole_process::signal(SIGTERM, function ($signo) {
            exit();
        });
        swoole_process::signal( SIGCHLD, function( $signo ) {
            while ($ret = swoole_process::wait(false)) {
                $pidx = $ret[ 'pid' ];
                print_r( $ret );
                print_r( self::$list );
                if( isset( self::$list[ $pidx ] ) )
                {
                    echo "SIGNAL: $signo\n";
                    $end = microtime(true);
                    $start = box::$list[$pidx]["start"];
                    echo ("##{$pidx} exit... [Runtime:" . sprintf("%0.6f", $end - $start) . "]").PHP_EOL;
                    unset( box::$list[$pidx] );
                }
                else
                {
                    echo "nono SIGNAL: $signo\n";
                }
            }
        });
    }
}


####################################################################################################
$http = new swoole_http_server("0.0.0.0",9501,SWOOLE_BASE);
//初始化swoole服务
$http->set(array(
    'task_worker_num' => 2,
    'worker_num'  => 2,
    'daemonize'   => 0, //是否作为守护进程,此配置一般配合log_file使用
    'max_request' => 1000,
    'dispatch_mode' => 2,
    'debug_mode' => 1,
    'log_file'    => './swoole.log',
));

$http->on('Start', function(){
        echo 'start pid#' . posix_getpid() . '#' . __LINE__ . PHP_EOL;
        echo SWOOLE_VERSION . " onStart\n";
} );
$http->on('WorkerStart', function( $serv , $worker_id) use ( $http ){
        // 在Worker进程开启时绑定定时器
        swoole_set_process_name( 'lau_php_worker' . posix_getpid() );
        // 只有当worker_id为0时才添加定时器,避免重复添加
        if( $worker_id == 0 ) {
            box::registerSingal();
            swoole_timer_tick(1000,function( $params ){
                box::processDo();
            });
        }
});
$http->on('request',function($request,$response) use ( $http ){
    echo '____request pid#' . posix_getpid() . '#' . __LINE__ . PHP_EOL;
    $out = json_encode(box::$list);
    $response->end($out);
});

$http->on( 'task', function($http, $taskId, $fromId, $request){
    echo '+++++task:'.$http->worker_pid.PHP_EOL;
    return ;
});

$server = $http;
$http->on( 'finish' , function($server, $taskId, $ret)
{
});
swoole_set_process_name( 'lau_php_main' . posix_getpid() );
$http->start();</code>

Reply content:

The log printed by the timer shows jitter, as follows:
timer: ##23496 ##2016-09-01 19:23:24
timer: ##23496 ##2016-09-01 19:23:25
timer: ##23496 ##2016-09-01 19:23:27
timer: ##23496 ##2016-09-01 19:23:27
timer: ##23496 ##2016-09-01 19 :23:28
timer: ##23496 ##2016-09-01 19:23:29
timer: ##23496 ##2016-09-01 19:23:30
timer: ##23496 ##2016- 09-01 19:23:31
timer: ##23496 ##2016-09-01 19:23:33
timer: ##23496 ##2016-09-01 19:23:33
timer: ##23496 ##2016-09-01 19:23:36
timer: ##23496 ##2016-09-01 19:23:37
timer: ##23496 ##2016-09-01 19:23:39
timer : ##23496 ##2016-09-01 19:23:39
timer: ##23496 ##2016-09-01 19:23:40
timer: ##23496 ##2016-09-01 19:23 :41
timer: ##23496 ##2016-09-01 19:23:42
timer: ##23496 ##2016-09-01 19:23:43
timer: ##23496 ##2016-09- 01 19:23:45

Is there a problem with the process signal registration in timer? Or is there a problem with using signal and server together?
The code is as follows:

<code><?php
class box{
    static $list = array();

    static function processDo()
    {
        $echo = 'timer: ##'. posix_getpid() . ' ##'. date( 'Y-m-d H:i:s').PHP_EOL;
        file_put_contents( '/tmp/xx.log' , $echo , FILE_APPEND );

        $process = new swoole_process( function( swoole_process $worker ){
            swoole_set_process_name( 'lau_php_process' . posix_getpid() );
            exec( 'php -i' , $output , $status );
            echo 'process:' . posix_getpid() . ':: exec.status' . $status . PHP_EOL;
            sleep(5);
            $worker->exit(1);
        });
        if (!($pid = $process->start())) {
        }
        box::$list[$pid] = array(
            "start" => microtime(true),
            "process" =>$process,
        );
    }

    static function registerSingal()
    {
        swoole_process::signal(SIGTERM, function ($signo) {
            exit();
        });
        swoole_process::signal( SIGCHLD, function( $signo ) {
            while ($ret = swoole_process::wait(false)) {
                $pidx = $ret[ 'pid' ];
                print_r( $ret );
                print_r( self::$list );
                if( isset( self::$list[ $pidx ] ) )
                {
                    echo "SIGNAL: $signo\n";
                    $end = microtime(true);
                    $start = box::$list[$pidx]["start"];
                    echo ("##{$pidx} exit... [Runtime:" . sprintf("%0.6f", $end - $start) . "]").PHP_EOL;
                    unset( box::$list[$pidx] );
                }
                else
                {
                    echo "nono SIGNAL: $signo\n";
                }
            }
        });
    }
}


####################################################################################################
$http = new swoole_http_server("0.0.0.0",9501,SWOOLE_BASE);
//初始化swoole服务
$http->set(array(
    'task_worker_num' => 2,
    'worker_num'  => 2,
    'daemonize'   => 0, //是否作为守护进程,此配置一般配合log_file使用
    'max_request' => 1000,
    'dispatch_mode' => 2,
    'debug_mode' => 1,
    'log_file'    => './swoole.log',
));

$http->on('Start', function(){
        echo 'start pid#' . posix_getpid() . '#' . __LINE__ . PHP_EOL;
        echo SWOOLE_VERSION . " onStart\n";
} );
$http->on('WorkerStart', function( $serv , $worker_id) use ( $http ){
        // 在Worker进程开启时绑定定时器
        swoole_set_process_name( 'lau_php_worker' . posix_getpid() );
        // 只有当worker_id为0时才添加定时器,避免重复添加
        if( $worker_id == 0 ) {
            box::registerSingal();
            swoole_timer_tick(1000,function( $params ){
                box::processDo();
            });
        }
});
$http->on('request',function($request,$response) use ( $http ){
    echo '____request pid#' . posix_getpid() . '#' . __LINE__ . PHP_EOL;
    $out = json_encode(box::$list);
    $response->end($out);
});

$http->on( 'task', function($http, $taskId, $fromId, $request){
    echo '+++++task:'.$http->worker_pid.PHP_EOL;
    return ;
});

$server = $http;
$http->on( 'finish' , function($server, $taskId, $ret)
{
});
swoole_set_process_name( 'lau_php_main' . posix_getpid() );
$http->start();</code>

This is normal for you. You can open the computer clock settings to see if the seconds are 4 seconds short and 5 seconds long? See details below

A while ago, someone in the Squirrel Club mentioned that the second hand in the Windows system moves faster for the first four seconds and slower for the next second. Then he said that it only started this year, which heralded drastic changes on the earth, and it was ridiculous to wait. Very disapproving. However, this phenomenon of different speeds turns out to be true. Now someone has provided an explanation, which is a problem with the program:

If you have paid careful attention, when you click on the clock in the lower right corner of the 2K/XP/2K3 system and let its second hand move, a very interesting phenomenon will appear: the numbers and the second hand change rapidly in the first four seconds. Five seconds feels like a long time, why is that?

The reason actually lies in the accuracy of that table.

If you have studied Windows C++ programming, you will know that WM_TIMER is a commonly used timer. But the accuracy of this timer is not very high. In the Windows Clock subroutine, WM_TIMER is actually used for timing. When the second hand is displayed, the update of the table is triggered by such a statement:

SetTimer (hWnd, TimerID, OPEN_TLEN, 0L);

SetTimer is very simple to use. After setting the Timer, you only need to re-fetch the current time and redraw the dial every time it is triggered. Then OPEN_TLEN is the trigger time of Timer. This time is a constant and is defined as 450 on the affected system, which is less than half a second.

What will happen if it is defined as 450ms? Let's look at a set of numbers. The first and third lines are the number of updates, and below them are the number of milliseconds for the update.

1 2 3 4 5 6 7 8
450 900 1350 1800 2250 2700 3150 3600

9 10 11 12 13 14 15 16 17
4050 4500 4950 5400 5850 6300 6750 7200 7650

You can see that the table is actually updated twice in the first second (

Then why is it designed like this? Probably because this watch just gives you a sense of time. As long as you don't make a mistake, the second-level response is not important... After all, there are not many people in this world who stare at the second hand and count beats all day long.

The above explanation comes from opal.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn