基于php的pcntl_alarm()写的同步定时器

2019-03-14  本文已影响0人  金星show
<?php
header("Content-Type:text/html;charset=utf8");
set_time_limit(0);
//ini_set('max_execution_time',0);
/**
 * 定时器
 * 监听alarm信号,并通过alarm信号来控制每次的执行.即收到alarm信号后开始执行定时器任务
 * 比如每十秒发送一次Alarm信号,那么每十秒就执行一次定时器任务
 * 如有事件支持时,比如Select或者Libevent等,则不再使用alarm信号来辅助
 */
class Timer
{
    //事件机制.为空时则使用alarm信号来完成定时器机制.不为空时依赖Select/Libevent等
    private static $_event = null;
    //任务列表
    private static $_taskList = array();
    //任务ID
    private static $_id = 1;

    /**
     * 初始化定时器
     * @param object $event
     */
    public static function init($event = null)
    {
        //如果没有事件,则安装一个alarm信号处理器
        echo "初始化成功,安装一个alarm信号处理器".PHP_EOL;
        pcntl_signal(SIGALRM, array('Timer', 'signalCallback'));
        //is_object($event) ? (self::$_event = $event) : (pcntl_signal(SIGALRM, array('Timer', 'signalCallback'), false));
    }

    /**
     * 添加任务
     * @param $callback string|array 回调函数
     * @param $args array 参数
     * @param $intervalSecond int 每次执行的间隔时间,单位秒,必须大于0
     * @param $isAlways bool|true 是否一直执行,默认为true. 一次性任务请传入false
     * @return int|false
     */
    public static function add($callback, array $args, $intervalSecond, $isAlways = true,$old_timer_id = '')
    {
        if ($intervalSecond <= 0 || !is_callable($callback)) {
            return false;
        }
        if (!is_null(self::$_event)) {
            //return self::$_event->add($callback, $args, $intervalSecond, $isAlways ? EventInterface::EVENT_TYPE_TIMER : EventInterface::EVENT_TYPE_TIMER_ONCE);
        } else {
            //echo '添加成功'.PHP_EOL;
            pcntl_alarm(1);
            $startTime = time() + $intervalSecond;
            $timerId = self::$_id++;

            if($old_timer_id){
                $timerId = $old_timer_id;
            }
            self::$_taskList[$timerId] = array($callback, $args, $startTime, $intervalSecond, $isAlways,$timerId);
            return $timerId;
        }
    }

    /**
     * 删除一个定时器
     * @param $timerId
     */
    public static function delOne($timerId)
    {
        if (!is_null(self::$_event)) {
            //self::$_event->delOne($timerId, EventInterface::EVENT_TYPE_TIMER);
        } else {
            unset(self::$_taskList[$timerId]);
        }
    }

    /**
     * 删除所有的定时器任务
     */
    public static function delAll()
    {
        self::$_taskList = array();
        pcntl_alarm(0);
        if (!is_null(self::$_event)) {
            //self::$_event->delAllTimer();
        }
    }

    /**
     * 信号处理函数
     */
    public static  function signalCallback()
    {
        //没有事件机制,并且队列不为空,则使用alarm信号
        if (is_null(self::$_event) && !empty(self::$_taskList)) {
            echo "定时器收到信号".PHP_EOL;
            //创建一个计时器,每秒向进程发送一个alarm信号。
            pcntl_alarm(1);
            self::_execute();
        }
    }

    /**
     * 执行任务
     */
    private static function _execute()
    {
        $nowTime = time();
        echo "开始执行".PHP_EOL;
        foreach (self::$_taskList as $timerId => $task) {
            //当前时间小于启动时间,则不启动该时间段任务
            if ($nowTime < $task[2]) {
                continue;
            }
            //如果是持续性定时器任务,则添加到下次执行的队伍中
            if ($task[4]) {
                self::add($task[0], $task[1], $task[3], $task[4],$task[5]);
            }
            //执行回调函数
            try {
                echo '任务id:'.$timerId.PHP_EOL;
                call_user_func_array($task[0], $task[1]);
            } catch (\Exception $e) {
                Log::write('execution callback function timer execute-' . $task[0] . ' throw exception' . json_encode($e), 'ERROR');
            }
            //删除本次已经执行的任务
            //unset(self::$_taskList[$timerId]);
        }
    }
}



Timer::init();
$timer_id1 = Timer::add('test',array('我是任务一'),5,true); //添加定时任务  5秒执行一次,某个方法。
$timer_id2 = Timer::add('test',array('我是任务二'),5,true);

Timer::delOne($timer_id1);
Timer::delOne($timer_id2);

try{
    while(true){
        pcntl_signal_dispatch();

        sleep(10);//模拟进程执行任务 挂起
        pcntl_signal_dispatch();
    }
}catch(\Exception $e){
    echo $e->getMessage();
}


function test($msg){
    echo $msg.'-'.time().PHP_EOL;
}


//接受任务 参数处理 定时信号  信号接收处理  抛出信号
上一篇下一篇

猜你喜欢

热点阅读