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 extension: A process extension of PHP, 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.
1 <?php 2/** 3 * Timer 4 */5 class Timer 6 {7//Save all Scheduled Tasks 8 public static $task = Array (); 9 10//Regular interval one public static $time = 1; 12 13/** 14 * Open service * @param $time INT * * * public static function run ($time = null) {if ($time) + {self:: $time = $time; 22} 23 Self::installhandler (); Pcntl_alarm (1); 25} 26/** 27 * Registered Signal processing function */public static function Installhandler () 30 {pcntl_signal (SIGALRM, Array (' Timer ', ' Signalhandler ')); 32} 33 34/** 35 * Signal Processing function: */Notoginseng public static function Signalhandler () self::task (); 40 Once the signal event is executed, the next Pcntl_alarm (self:: $time) is triggered; 42} 43 44/** 45 * Execute CALLBACK-*/public static function task ()$ {(self:: $task)) 50 {//no task returned; 52 } (self:: $task as $time = + $arr) ($current = time (); 56 ($arr as $k = + $job) 58 {//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) 65 {//Current time has perform task 66 67 Call the callback function and pass the parameter Call_user_func_array ($func, $ARGV); 69 70//Delete the task unset (self:: $task [$time] [$k]); ($persist) 74 {//If you doPersisted, the array is written, waiting for the next wake to self:: $task [$current + $interval] = $job; (Self:: $task [$time]) 79 {80 Unset (self:: $task [$time]); 81} 82} 83} 84 85/** 86 * Add Task */-public static function Add ($interval, $func, $argv = Array (), $persist = False) (Is_null ($interval)) 91 {94 return; $time = time () + $interval; 95//write timed task to self:: $task [$time] = Array (' func ' = = $func, ' argv ' = = $argv, ' interval ' = + $interval, ' Persist ' = $persist); 97} 98 99/**100 * Delete all timer Tasks 101 */102 Public Function Dellall () 103 {104 Self:: $task = Array (); 105}106}
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.
1 <?php 2 3 class Dojob 4 {5 Public function Job ($param = Array ()) 6 {7 $time = time (); 8 Echo "Time: {$time}, Func:". Get_class (). "::". __function__. " (". Json_encode ($param).") \ n "; 9 }10}
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.
1 <?php 2 3 require_once (__dir__. " /timer.php "); 4 require_once (__dir__. " /dojob.php "); 5 6 7 Timer::d Ellall (); 8 9 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 (); (1) + ( 1); Pcntl_signal_dispatch (); 20}
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
- The current process cannot exit until the signal is received. Here I use a loop where the condition is always true. 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 will not terminate , even if the process is blocked, this scenario is used in a service that has been running.
- Currently PHP only supports triggers in seconds, and does not support smaller time units, which is basically sufficient for bit-timed tasks
= = Divider Line =========
2015.8.11 Errata!
Now find the PHP millisecond timer, ^_^, write it over a period of time!
Pure PHP Implementation Timer Task (timer)