Heim > Artikel > Backend-Entwicklung > Der Timer im Swoole-Server ist ungenau und zittert. Bitte antworten Sie.
Das vom Timer gedruckte Protokoll zeigt Jitter wie folgt an:
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
Gibt es ein Problem mit der Prozesssignalregistrierung im Timer? Oder gibt es ein Problem bei der gemeinsamen Verwendung von Signal und Server?
Der Code lautet wie folgt:
<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>
Das vom Timer gedruckte Protokoll zeigt Jitter wie folgt an:
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
Gibt es ein Problem mit der Prozesssignalregistrierung im Timer? Oder gibt es ein Problem bei der gemeinsamen Verwendung von Signal und Server?
Der Code lautet wie folgt:
<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>
Das ist für Sie normal. Sie können die Uhreinstellungen des Computers öffnen, um zu sehen, ob die Sekunden 4 Sekunden kurz und 5 Sekunden lang sind. Einzelheiten finden Sie weiter unten
Vor einiger Zeit erwähnte jemand im Squirrel Club, dass sich der Sekundenzeiger im Windows-System in den ersten vier Sekunden schneller und in der nächsten Sekunde langsamer bewegt. Dann sagte er, dass es erst in diesem Jahr begonnen habe, was drastische Veränderungen auf der Erde ankündige, und es sei lächerlich, darauf zu warten. Sehr missbilligend. Dieses Phänomen der unterschiedlichen Geschwindigkeiten stellt sich jedoch als wahr heraus. Jetzt hat jemand eine Erklärung geliefert, was ein Problem mit dem Programm ist:
Wenn Sie genau aufgepasst haben, klicken Sie auf die Uhr in der unteren rechten Ecke des 2K/XP/2K3-Systems und lassen Sie den Sekundenzeiger laufen. Es erscheint ein sehr interessantes Phänomen: Die Zahlen und der Sekundenzeiger ändern sich schnell Die ersten vier Sekunden kommen mir sehr lang vor, die fünfte Sekunde kommt mir sehr lang vor.
Der Grund liegt tatsächlich in der Genauigkeit dieser Tabelle.
Wenn Sie Windows C-Programmierung studiert haben, wissen Sie, dass WM_TIMER ein häufig verwendeter Timer ist. Die Genauigkeit dieses Timers ist jedoch nicht sehr hoch. In der Windows-Clock-Unterroutine wird WM_TIMER tatsächlich für die Zeitmessung verwendet. Wenn der Sekundenzeiger angezeigt wird, wird die Aktualisierung der Tabelle durch eine solche Anweisung ausgelöst:
SetTimer (hWnd, TimerID, OPEN_TLEN, 0L);
SetTimer ist sehr einfach zu verwenden. Nach dem Einstellen des Timers müssen Sie nur die aktuelle Uhrzeit abrufen und das Zifferblatt jedes Mal neu zeichnen, wenn er ausgelöst wird. Dann ist OPEN_TLEN die Triggerzeit des Timers. Diese Zeit ist eine Konstante und wird auf dem betroffenen System als 450 definiert, was weniger als einer halben Sekunde entspricht.
Was passiert, wenn es als 450 ms definiert ist? Schauen wir uns eine Reihe von Zahlen an. Die erste und dritte Zeile geben die Anzahl der Aktualisierungen an und darunter die Anzahl der Millisekunden für die Aktualisierung.
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
Wie Sie sehen können, wird die Tabelle tatsächlich zweimal in der ersten Sekunde (
Warum ist es dann so konzipiert? Wahrscheinlich, weil diese Uhr Ihnen nur ein Gefühl für die Zeit vermittelt. Solange Sie keinen Fehler machen, ist die Reaktion auf der zweiten Ebene nicht wichtig ... Schließlich gibt es nicht viele Menschen auf dieser Welt, die auf die Sekunde starren Den ganzen Tag über Hand- und Zählschläge.
Die obige Erklärung stammt von Opal.