예제 #1
0
        /// <summary>
        /// 添加任务
        /// </summary>
        /// <param name="task">延时任务</param>
        /// <returns></returns>
        public bool AddTask(TimeTask task)
        {
            if (!task.IsWaiting)
            {
                return(false);
            }

            if (task.TimeoutMs < _currentNeedle + _tickSpan)
            {
                // 任务已经过期,无法添加
                return(false);
            }

            // 是否可以放入当前时间轮
            if (task.TimeoutMs < _currentNeedle + _wheelSpan)
            {
                // 任务已经过期,无法添加
                // 计算过期时间戳所属的时间槽
                var tickCount = task.TimeoutMs / _tickSpan;
                var slotIndex = (int)(tickCount % _slotCount);

                var slot = _timeSlots[slotIndex];
                slot.AddTask(task);

                // 设置成功,说明该时间槽已过期出队,需要重新入队
                // 在同一轮循环内,同一个槽的slotTimeoutMs是一样的
                var slotTimeoutMs = tickCount * _tickSpan;
                if (slot.SetExpiration(slotTimeoutMs))
                {
                    // 注意这里有个特殊情况:
                    // slotTimeoutMs是按照tickSpan裁剪得到的值,可能会小于当前时间,
                    // 意味着这里入队的slot已经超时,TimingWheelTimer会将该slot立即出队。
                    _delayQueue.TryAdd(slot);

                    /*
                     * 举个例子,需要结合TimingWheelTimer.Step方法来分析:
                     * 假如第1层时间轮是秒级(1s 60个槽),那么第2层时间轮就是分钟级(60s 60个槽),第3层时间轮是小时级(3600s,60个槽);
                     * 第1层时间轮启动时间是12点钟(currentNeedle=12:00:00),1小时1分后(当前时间13:01:00)加入第1个延时任务,延时时间是1s;
                     * 该任务TimeoutMs是13:01:01,虽然是1s后过期,但由于currentNeedle=12:00:00,所以计算后实际会进入第3层时间轮;
                     * 在第3层时间轮计算得到的slotTimeoutMs为13:00:00,已过期,所以solt在入队后又会立即出队(由TimingWheelTimer.Step.TryTake处理);
                     * 那么出队后重新计算,第1层时间轮的currentNeedle会变成13:00:00,所以计算后任务会进入第2层时间轮;
                     * 在第2层时间轮计算得到的slotTimeoutMs为13:01:00,还是过期,所以solt在入队后又会立即出队(由TimingWheelTimer.Step.TryTakeNoBlocking处理);
                     * 那么出队后重新计算,第1层时间轮的currentNeedle会变成13:01:00,延时任务将留在第1层时间轮,等待1s后过期。
                     */
                }

                return(true);
            }
            // 超出当前时间轮,则放入下一层
            else
            {
                CreateNextWheel();
                return(_nextWheel.AddTask(task));
            }
        }
예제 #2
0
 /// <summary>
 /// 添加任务
 /// </summary>
 /// <param name="timeTask">延时任务</param>
 private void AddTask(TimeTask timeTask)
 {
     // 添加失败,说明该任务已到期,需要执行了
     if (!_timingWheel.AddTask(timeTask))
     {
         if (timeTask.IsWaiting)
         {
             // TODO:是否放入自定义线程池
             Task.Run(timeTask.Run);
         }
     }
 }
예제 #3
0
        /// <summary>
        /// 添加任务
        /// </summary>
        /// <param name="timeoutMs">过期时间戳,绝对时间</param>
        /// <param name="delegateTask">延时任务</param>
        /// <returns></returns>
        public ITimeTask AddTask(long timeoutMs, Action delegateTask)
        {
            Requires.NotNull(delegateTask, nameof(delegateTask));

            _lock.EnterReadLock();
            try
            {
                var task = new TimeTask(timeoutMs, delegateTask);
                AddTask(task);
                return(task);
            }
            finally
            {
                _lock.ExitReadLock();
            }
        }
예제 #4
0
        /// <summary>
        /// 移除定时任务
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public bool RemoveTask(TimeTask task)
        {
            lock (_lock)
            {
                if (task.TimeSlot == this)
                {
                    if (_tasks.Remove(task))
                    {
                        task.TimeSlot = null;
                        _taskCount.Decrement();
                        return(true);
                    }

                    return(false);
                }
            }

            return(false);
        }
예제 #5
0
        /// <summary>
        /// 添加任务
        /// </summary>
        /// <param name="task">延时任务</param>
        /// <returns></returns>
        public bool AddTask(TimeTask task)
        {
            if (!task.IsWaiting)
            {
                return(false);
            }

            if (task.TimeoutMs < _currentNeedle + _tickSpan)
            {
                // 任务已经过期,无法添加
                return(false);
            }

            // 是否可以放入当前时间轮
            if (task.TimeoutMs < _currentNeedle + _wheelSpan)
            {
                // 任务已经过期,无法添加
                // 计算过期时间戳所属的时间槽
                var tickCount = task.TimeoutMs / _tickSpan;
                var slotIndex = (int)(tickCount % _slotCount);

                var slot = _timeSlots[slotIndex];
                slot.AddTask(task);

                // 设置成功,说明该时间槽已过期出队,需要重新入队
                // 在同一轮循环内,同一个槽的slotTimeoutMs是一样的
                var slotTimeoutMs = tickCount * _tickSpan;
                if (slot.SetExpiration(slotTimeoutMs))
                {
                    _delayQueue.TryAdd(slot);
                }

                return(true);
            }
            // 超出当前时间轮,则放入下一层
            else
            {
                CreateNextWheel();
                return(_nextWheel.AddTask(task));
            }
        }
예제 #6
0
        /// <summary>
        /// 添加定时任务
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public void AddTask(TimeTask task)
        {
            var done = false;

            while (!done)
            {
                // 先从其它队列移除掉
                // 在lock之外操作,避免死锁
                task.Remove();

                lock (_lock)
                {
                    if (task.TimeSlot == null)
                    {
                        _tasks.AddLast(task);
                        task.TimeSlot = this;
                        _taskCount.Increment();
                        done = true;
                    }
                }
            }
        }