How to use pure PHP to implement timer task (timer), timers timer
Timer tasks, common in Web applications, how to use PHP to implement timer tasks, there are roughly two scenarios: 1. Use the crontab command, write a shell script, invoke the PHP file in the script, and then execute the script on a regular basis, 2) with Ignore_user_abort () and Set_time_limit () to make the script run out of the browser. The former is the use of Linux features, and PHP itself is not much of a relationship, the latter use of limited scenarios, and can only be triggered by an HTTP request to the script, after execution exit. So how do we use pure PHP to achieve purely timer tasks, and to adapt to the business needs of understanding the task?
Basic knowledge
This program is developed under Linux and runs in CLI mode, which is a brief introduction to the basics.
CLI: PHP command-line mode, common Web applications use FPM;
process: The process is the basic unit of program operation, the process is independent and non-interference, there is a separate running space, each process has a process control block;
Interprocess communication: Since the process is running independently, we need a mechanism to ensure the exchange of different process information, inter-process communication mainly include: Pipeline, IPC (shared memory, signal, Message Queuing), sockets;
pcntl Extensions: PHP is a process extension, mainly used in the Pcntl_alarm () function, detailed information please check the official website.
Implementation principle
Use a three-dimensional array to save all the tasks that need to be performed, the first index is a timestamp, the value is the method to perform the task, the callback parameter, and so on, the following array form:
Array ( ' 1438156396 ' = = Array ( array (1,array (' Class ', ' Func '), Array (), true), ) Description: 1438156396 The timestamp array (1,array (' Class ', ' Func '), Array (), true) is followed by the parameter: execution interval, callback function, parameter passed to the callback function, whether persisted (Ture is persisted in the data, or deleted after execution)
These tasks can be methods of any class. Since it is a timed task, we need a similar to the timing of the East, this scheme uses the semaphore to do, every second to the current process to send SIGALRM signal, and capture the signal, trigger signal processing function, loop through the data, to determine whether there is the current time to perform the task. If any, it is triggered by a callback method, and the parameter is passed to the method.
<?php/** * Timer */class Timer {//Save all Scheduled Tasks public static $task = Array (); Regular interval public static $time = 1; /** * Open service * @param $time int */public static function run ($time = null) {if ($time) {self:: $time = $tim E } self::installhandler (); Pcntl_alarm (1); }/** * Register signal Processing function */public static function Installhandler () {pcntl_signal (SIGALRM, Array (' Timer ', ' Signalhandl Er ')); }/** * Signal processing function */public static function Signalhandler () {self::task (); Once the signal event is executed, the next pcntl_alarm is triggered (self:: $time); }/** * Executes the callback */public static function task () {if (The Empty (self:: $task)) {//No task, returns return; } foreach (self:: $task as $time = + $arr) {$current = time (); foreach ($arr as $k + $job) {//traverse each task $func = $job [' func '];/* callback function */$argv = $job [' argv '];/* Callback function parameter */ $interval = $job [' interval ']; /* Time interval */$persist = $job [' persist ']; /* Persistent */if ($current = = $time) {//Current time has execute task//Call callback function, and pass parameter Call_user_func_array ($func, $ARGV); Delete the task unset (self:: $task [$time] [$k]); if ($persist) {///if persisted, the array is written, waiting for the next wake self: $task [$current + $interval] = $job; }} if (Empty (self:: $task [$time])) {unset (self:: $task [$time]); }}}/** * Add task */public static function Add ($interval, $func, $argv = Array (), $persist = False) {if (Is_null ($interval)) {return; } $time = time () + $interval; Write timed Task self:: $task [$time] = Array (' func ' = + $func, ' argv ' = = $argv, ' interval ' + $interval, ' persist ' =>$ persist); }/** * Delete all timer tasks */Public Function Dellall () {self:: $task = Array (); } }
This is the core of the timer class, there is a static variable to save all the tasks that need to be performed, why is this static? We think for ourselves. When the process accepts the SIGALRM signal, it triggers the Signalhandler function, and then iterates through the array to see if there is a task to be performed at the current time. Have a callback, pass the parameters, delete the current job, and then check whether to do the persistence task, then continue to write the current job to the event array to wait for the next trigger, and then set an alarm signal for the current process. It can be seen that this timer, as long as the trigger will be triggered from the inside again, the purpose of the loop.
<?php class Dojob {public function job ($param = Array ()) { $time = time (); echo "Time: {$time}, Func:". Get_class (). "::". __function__. " (". Json_encode ($param).") \ n "; } }
This is a callback class and function, to facilitate the description, adding a lot of debugging information. The timer class and callbacks are all there, so let's see what the usage scenario is.
<?php require_once (__dir__. " /timer.php "); Require_once (__dir__. " /dojob.php "); Timer::d ellall (); Timer::add (1, Array (' dojob ', ' job '), Array (), true); Timer::add (3, Array (' dojob ', ' job '), Array (' A ' =>1), false); echo "Time start:". Time (). " \ n "; Timer::run (); while (1) { sleep (1); Pcntl_signal_dispatch (); }
The code is very short, registering two jobs here, then running the timer, capturing the signal trigger action in an infinite loop, and failing to capture a handler function that will not trigger a pre-registration. Such a self-looping timer was developed. The results are as follows:
Like the task we added in our scene class, we performed two tasks at 90, a job with no parameters persisted, a job with non-persisted parameters, and then non-persisted jobs were no longer executed.
Summarize
1. Before the signal is received, the current process cannot exit. Here I used the condition to always be the true loop. In our actual production environment, we need to create such a prerequisite, for example, we have a set of services, these services are always running, whether it is IO access, waiting for the socket link, and so on, The current service does not terminate, even if the process is blocked, which is a scenario that is used in a service that has been running.
2, currently PHP only supports the trigger in seconds, does not support a smaller time unit, the bit-timed task is basically enough
The above is the whole content of this article, I hope that everyone's study has helped.
http://www.bkjia.com/PHPjc/1041338.html www.bkjia.com true http://www.bkjia.com/PHPjc/1041338.html techarticle How to use pure PHP to implement timer task (timer), Timer Timer task, the Web application is more common, how to use PHP to implement timer tasks, there are roughly two scenarios: 1) to make ...