Pure PHP Implementation Timer Task (timer)

Source: Internet
Author: User
Tags add foreach array empty execution php file socket time interval
Timer task, in the Web application is more common, how to use PHP to implement the timer task, there are roughly two scenarios: 1 Use the crontab command, write a shell script, in the script to call the PHP file, and then execute the script regularly, 2 with the use of Ignore_user_abort () and Set_time_limit () to run the script 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 the script, after execution exit.   So how do we use pure PHP to achieve pure timer tasks, and to meet the task business needs?   Basic knowledge This program is developed under Linux and runs in CLI mode, which is a brief introduction to basic knowledge. cli:php command line mode, common Web applications use FPM; process: Process is the basic unit of the program running, the process is independent operation and Non-interference, there is independent running space, each process has a process control block; interprocess communication: Now that the process is running independently, We need a mechanism to ensure the exchange of information of different processes, inter-process communication mainly includes: Pipeline, IPC (shared memory, signal, Message Queuing), socket; PCNTL extension: A process extension of PHP, mainly use the Pcntl_alarm () function, please refer to the official website for details. The realization principle uses a three-dimensional array to save all tasks that need to be performed, a first index is a timestamp, a value is a method for performing a task, a callback parameter, and so on, in the form of an array as follows:
Array (
        ' 1438156396 ' => Array (
                1,array (' Class ', ' Func '), Array (), true))
1438156396 timestamp
Array (1,array (' Class ', ' Func '), Array (), true) 
argument in sequence: execution interval, callback function, arguments passed to the callback function, persisted ( Ture is kept in the data, or deleted once after execution.
    These tasks can be a method of any class. Since it is a timed task, we need a similar time, this scheme uses semaphores to do, every second to the current process to send SIGALRM signal, and capture the signal, triggering signal processing functions, loop through the data, to determine whether there is the current times need to perform tasks. If so, it is triggered by a callback and passes the parameter 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//timed interval one public static $time = 1; 12 13/** 14 * Open service * @param $time INT/* public static function run ($time = n
 ull {if ($time) {self:: $time = $time;
 Self::installhandler ();
 Pcntl_alarm (1);          25} 26/** 27 * Registration Signal processing Function-* public static function Installhandler () 30
 {pcntl_signal (SIGALRM, Array (' Timer ', ' Signalhandler ')); 32} 33 34/** 35 * Signal processing function +/Panax Notoginseng public static function Signalhandler () 3
 8 Self::task ();
 40//Once the signal event is executed, the next pcntl_alarm is triggered (self:: $time);       42} 43 44/** 45 * Execute callback 46  * * public static function task () {50 if (empty) (self:: $task)) {//No any
 Service, return to the Wu;  foreach (self:: $task as $time => $arr) $current =
 Time (); foreach ($arr as $k => $job) 58 {//Traverse each mission $fun    c = $job [' func '];    /* Callback function/* $argv = $job [' argv '];    /* Callback function parameter * * $interval = $job [' interval '];    /* Time interval * * $persist = $job [' persist '];                     /* Persistent/"if" ($current = = $time) 65 {//The current time has the execution task 66 67
 Call the callback function and pass the argument to Call_user_func_array ($func, $ARGV);
 69 70//Delete the task unset (self:: $task [$time] [$k]);
 72}if ($persist) 74 {//If persisted, the array is written, waiting for the next wake-up call 75
 Self:: $task [$current + $interval] = $job;                 Empty (self:: $task [$time]) 79 {80
 Unset (self:: $task [$time]); 81} 82} 83} 84 85/** 86 * Add task static function Add ($interval, $func, $argv = Array (), $persist = False) {Is_null ($interva
 L)) (a);
 The $time = time () + $interval;  95//write timed Task self:: $task [$time] = Array (' func ' => $func, ' argv ' => $argv, ' interval ' => $interval,
 ' Persist ' => $persist);         97} 98 99/** 100 * Delete all timer tasks/102 Public Function Dellall () 103  {Rule 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? Everyone thinks for themselves. When the process receives the SIGALRM signal, triggers the Signalhandler function, then sequentially iterates through the array to see if there is a task to be performed at the current time. There is a callback, and the parameters are passed, delete the current job, and then check whether you want to do a persistent task, continue to write the current job to the event array, wait for the next trigger, and finally set an alarm signal for the current process
 1 <?php
 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     }
This is a callback class and function, to facilitate the description, adding a lot of debugging information. The timer class and the callback are all there, so let's see what the use scenario is.
 1 <?php
 3 require_once (__dir__.) /timer.php ");
 4 require_once (__dir__.) /dojob.php ");
 7 Timer::d ellall ();
 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 ();
The code is very short, there are two jobs registered, then run the timer, in an infinite loop to catch the signal trigger action, if not capture will not trigger the registration of the handler function. Such a self cycle timer is developed. The results are as follows: As we add to the scene class,   At 90, two tasks were performed, a job with no parameters persisted, a job that was not persisted with parameters, and then the Non-persistent job was no longer executed. Summary before receiving the signal, the current process cannot exit. Here I used the condition that the loop is always true. In our actual production environment, we need to create such a prerequisite, for example, we have a set of services that are always running, whether it is IO access, wait for the socket link, etc. The current service will not terminate, even if the process is blocking the problem, this scenario, that is, there is a running service to use. At present, PHP only supports the trigger in seconds, does not support a smaller time unit, the bit timing task is basically enough

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.