当前位置:首页>Linux>搞懂时间轮算法,才算真正入门 Linux 内核定时机制

搞懂时间轮算法,才算真正入门 Linux 内核定时机制

  • 2026-06-21 22:46:05
搞懂时间轮算法,才算真正入门 Linux 内核定时机制

大家好,我是蟹老板~

今天周六补班,最近在优化我们系统的定时任务模块时,跟 Linux 时间轮算法杠上了。

说真的,很多人学 Linux 网络编程的时候,会把 epoll、Reactor、协程吹得天花乱坠。可真到了线上,最容易把服务拖死的,往往是“时间”。

是的,就是如何高效管理海量定时任务!

我第一次真正理解 Linux 时间轮算法的时候,有种“卧槽原来还能这样”的感觉。

它不像红黑树那么优雅,也不像跳表那么性感。

但它特别像一个在机房待了十年的老运维:

不讲武德,只讲效率。

今天这篇文章,我想用一个干了很多年后端、被线上事故毒打过无数次的老程序员视角,聊聊 Linux 时间轮算法到底是怎么回事。

看完你会明白:为什么Linux内核选它,为什么Netty在用它,以及——最重要的一点——什么时候千万别用它

一、为啥要搞时间轮?

定时器的本质很简单,就是告诉系统,“xx毫秒后,帮我干个活”。

很多新人第一次写定时任务的时候,会这么写:

while (true) {    sleep(1);    check_timeout_tasks();}

甚至现在不少业务系统还这样。

功能当然能跑。

可问题是——任务一多,系统立刻开始抽风。

举个最经典的场景。

假设你有 100 万个连接。

每个连接都需要:

  • 60 秒心跳检测

  • 超时关闭

  • 延迟重试

你怎么办?

很多人第一反应是:

“那我存个时间戳呗。”

于是代码开始长这样:

struct Connection {    int fd;    long expire;};std::vector<Connection> conns;

然后每秒扫描一次。

for (auto &conn : conns) {    if (conn.expire < now) {        close(conn.fd);    }}

看着是不是还挺合理的?

问题来了。

100 万连接。

你每秒扫一遍。

意味着什么?

意味着 每个时钟中断去遍历百万个节点,CPU直接原地升天。

就比如你开了一个邮局,所有信件都堆在一个大篮子里。来了新信,你得从头翻一遍,找到它该排的位置插进去。来十万封信,你就得翻十万遍——这不是在解决问题,这是在培养耐心。

内核大佬们可没时间这么捣腾。大佬George Varghese和Tony Lauck在SOSP上发表了一篇论文,提出了一个现在来看仍然惊艳的思路——时间轮算法。

核心特别简单:别再用有序链表的思路去折腾了,咱们换个角度,把定时器当成钟表盘上的刻度来管理,时间复杂度是 O(1),也就是说,无论有多少个定时器,添加、删除、触发操作的效率都几乎不变。这不就是我们想要的么?

二、时间轮原理

时间轮算法的核心思想,就像钟表里的齿轮转动。Linux 内核用多级时间轮(也叫分层时间轮)来实现,它由多个层级组成,每个层级都是一个时间轮,就像多个齿轮嵌套在一起。最外层齿轮转一圈,内层齿轮就转一格,依次类推。每个时间轮上有很多槽位,每个槽位挂着一堆定时器。

很多文章一上来就讲:

  • tick

  • slot

  • round

  • cascade

  • hierarchy

看得人头皮发麻,其实核心逻辑并不复杂。

假设现在有一个钟表。

0 1 2 3 4 5 6 7 8 9

每秒走一格。

现在有几个任务:

任务延迟
A2 秒
B5 秒
C12 秒

那么:

  • A 放 2

  • B 放 5

  • C 放 2

等等。

C 为什么也放 2?

因为时间轮只有 10 格。

12 % 10 = 2。

那怎么区分 A 和 C?

答案是:

圈数。

也叫 round。

A:

2 秒后触发round = 0

C:

12 秒后触发round = 1

时间轮每转一圈。

round--。

当 round == 0 时。

任务真正执行。

是不是一下就通了?

2.1 单层时间轮

理解时间轮,最好从单层开始。

假设你有一个大小为8的数组,每个位置叫一个“槽位”(bucket)。我们让一个时针每隔1秒走一格。当前指针指向槽i时,就把槽i里挂的所有定时任务统统触发掉。走完一圈8秒,再从头开始——是不是特别像一根秒针在表盘上打转?

#define WHEEL_SIZE 256#define WHEEL_MASK (WHEEL_SIZE - 1)struct timer_node {    void (*callback)(void *arg);    void *arg;    unsigned long expires;    // 绝对过期时间(单位:tick)    struct list_head entry;};struct timer_wheel {    struct list_head slots[WHEEL_SIZE];    unsigned long current_slot;};

插入任务时,计算它应该落在哪个槽位:slot_index = (expires - now) & WHEEL_MASK。如果expires - now正好等于1个tick,丢到邻位;等于WHEEL_SIZE,还丢在当前位置,但需要带一圈round计数,否则以为马上过期就乱套了。至于round计数怎么带,后面的多级轮子再展开。

插入O(1),删除O(1),这是什么概念?哈希表的定时器版本!

但天下没有免费的午餐——单层时间轮的覆盖范围极其有限。假设每个tick=10ms、256个槽,整圈合计也就2.56秒,超过这个时间范围的定时器就没法直接存了。解决办法要么硬拖多圈(带round),但这样过期检测就不是O(1)了;要么扩容——你试试把WHEEL_SIZE开到65536,直接把整个二级缓存的局部性打没了。

所以啊,单层时间轮特别适合短期、密集、高精度要求不高的场景。像网络重传超时(比如TCP的RTO)、用户态心跳检修,这些落在100ms~10s区间的任务非常香但如果你的业务动不动就要延迟一小时执行任务,用单层时间轮就是给自己找麻烦——要么数组巨大内存吃不消,要么多圈后性能直线下降。

2.2 多级时间轮

Linux这帮大牛当然不会满足于单层的限制。他们搞了一个优雅的五级结构来解决这个矛盾——TV1管近期,TV2到TV5一级级往上覆盖,越往上时间跨度越大牺牲的分辨率也越大。任务超出当前级容量就溢出到上级,上级到期的任务再级联回本级。

#define TVR_BITS 8   // 第一级 2^8 = 256#define TVN_BITS 6   // 第二~五级 2^6 = 64struct timer_vec_root {    struct list_head vec[TVR_SIZE];  // 第一级:0-255};struct timer_vec {    struct list_head vec[TVN_SIZE];  // 第二到五级:各64个槽位};struct tvec_base {    struct timer_vec_root tv1;  // 近期定时器    struct timer_vec tv2;       // 中期定时器    struct timer_vec tv3;    struct timer_vec tv4;    struct timer_vec tv5;       // 最远期定时器    unsigned long timer_jiffies; // 当前时间指针};

怎么理解这个结构?假设HZ=1000(每个tick=1ms):

  • TV1(256槽):覆盖0~255ms,精度1ms

  • TV2(64槽×256ms):覆盖256ms~16.383秒

  • TV3(64槽×16.384秒):覆盖约17分钟~18.6小时

  • TV4和TV5逐级推更长时间范围

哪个更有趣?TV2一个槽位打包了TV1整张轮(256ms),TV3一个槽位打包了整个TV2和TV1!这种嵌套设计可以把长达数日的时间跨度压缩到几个不大的数组中,同时保留了O(1)的插入和到期检测性能。

当一个定时器的expires落在256ms~16.383秒之间,它就落到TV2的一个槽里,不需要动用TV3及以上的轮子。等时钟推进到它所在的那一组时,再级联回TV1。有点类似钟表的秒分时联动——秒针走完一圈,分针推一步,拉出下一分内的秒刻度。

级联机制(cascade) 是这套设计的灵魂之处:

staticintcascade(struct tvec_base *basestruct timer_vec *tv, int index){    struct list_head *list = tv->vec + index;    struct timer_list *timer;    // 将该槽的所有定时器重新插入时间轮    list_for_each_entry_safe(timer, tmp, list, entry) {        __internal_add_timer(base, timer);  // 重新计算层级    }    INIT_LIST_HEAD(list);    return index;}

每次时钟中断,timer_jiffies递增,TV1的当前槽被执行并清空。当timer_jiffies增长到TV1边界时,TV2相应槽被触发cascade,把里面的定时器按剩余时间重新塞回TV1对应的槽——这种懒处理的妙处在于,TV2整层都不需要高频扫描,只用时指针到达时一次性迁移。长时任务在绝大多数时间只待在高层数组里“睡大觉”,连链表遍历的压力都没有。

我在调网络网关时曾经用单机hotplug压到10万个tcp timer,内核的timer轮几乎感觉不到压力,CPU在0.3%附近波动。要是改用有序链表的话,你说要挂多少。这,就是多级时间轮的威力。

——敲黑板,这里必须提一嘴——低精度定时器的时间轮精度受HZ限制。HZ=100时,定时器精度只能到10ms,对毫秒级甚至微秒级精度需求完全无能为力。所以后面高精度定时器(hrtimer)子系统引入时,就把时间轮换成了红黑树(timerqueue),因为高精度定时器的到期时间是稀疏且随机分布的,时间轮在面对纳秒级精度需求时,要么需要一个巨大且大部分为空的时间轮(效率极低),要么精度崩坏。两种定时器场景不同,各司其职。

2.3 用户态的时间轮

说完了内核的多级轮子,咱们把目光拉回用户空间。

Java圈有Netty的HashedWheelTimer,C++这边呢?

很多网络库(比如muduo、evpp)自己也手撸过类似的东西。你有没有好奇过“Hashed”这个前缀啥意思?把定时器的deadline当key,用哈希法定位槽位——和内核那个线性推进jiffies的思路不太一样。说白了就是用空间换时间,加个hash的壳,让插入和删除都变成O(1)。

#include<atomic>#include<chrono>#include<condition_variable>#include<functional>#include<mutex>#include<thread>#include<vector>#include<list>#include<memory>using TimerTask = std::function<void()>;struct TimeoutEntry {    uint64_t deadline;          // 绝对到期时间(ms)    TimerTask callback;    // 还可以加cancel标志,为了简单先不写};class HashedWheelTimer {public:    explicitHashedWheelTimer(int ticksPerWheel = 512,                              int tickDurationMs = 100)        : wheel_(ticksPerWheel),          tickDurationMs_(tickDurationMs),          currentTick_(0),          running_(true) {        worker_ = std::thread(&HashedWheelTimer::workerLoop, this);    }    ~HashedWheelTimer() {        running_ = false;        cv_.notify_one();        if (worker_.joinable()) worker_.join();    }    // 添加一个延迟任务,delayMs单位毫秒    voidaddTimer(uint64_t delayMs, TimerTask task){        uint64_t deadline = getCurrentTimeMs() + delayMs;        // 计算槽位:基于延迟的绝对时间        int slot = (deadline / tickDurationMs_) % wheel_.size();        std::lock_guard<std::mutex> lock(mutex_);        wheel_[slot].push_back({deadline, task});    }private:    std::vector<std::list<TimeoutEntry>> wheel_;    const int tickDurationMs_;          // 每个tick的毫秒数    std::atomic<uint64_t> currentTick_; // 当前已经走过的tick数    std::atomic<bool> running_;    std::thread worker_;    std::mutex mutex_;    std::condition_variable cv_;    uint64_tgetCurrentTimeMs(){        auto now = std::chrono::steady_clock::now().time_since_epoch();        return std::chrono::duration_cast<std::chrono::milliseconds>(now).count();    }    voidworkerLoop(){        auto nextTickTime = std::chrono::steady_clock::now();        while (running_) {            // 1. 等待到下一个tick            {                std::unique_lock<std::mutex> lock(mutex_);                cv_.wait_until(lock, nextTickTime, [this] { return !running_; });            }            if (!running_) break;            // 2. 更新当前tick,并处理该槽位的所有任务            uint64_t tick = currentTick_.fetch_add(1);            int slot = tick % wheel_.size();            std::list<TimeoutEntry> bucket;            {                std::lock_guard<std::mutex> lock(mutex_);                bucket.swap(wheel_[slot]);            }            uint64_t now = getCurrentTimeMs();            for (auto& entry : bucket) {                // 严谨起见,这里可以判断 deadline <= now                if (entry.deadline <= now + tickDurationMs_) {                    entry.callback();                } else {                    // 理论上不应该发生,多圈任务我们没做级联,先忽略                    // 后面会讲到多圈怎么办                }            }            // 3. 计算下一个tick的绝对时间            nextTickTime += std::chrono::milliseconds(tickDurationMs_);        }    }};

默认tickDurationMs_ = 100ms意味着所有定时器的精度最多误差±100ms。绝大多数网络场景其实无所谓——TCP超时重传差个几十毫秒,人根本感觉不到。但如果你拿这玩意儿去做量化交易里的价格推送延迟控制,我劝你善良。

worker是单线程驱动的。假设你某个槽位挂了上千个任务,一个tick里就要把这些回调全部执行完。如果某个回调里不小心写了同步DB查询或者RPC调用——恭喜你,整个时间轮卡死在这一槽。后续所有tick全部延迟,积压的任务越来越多,最后雪崩式崩溃。这不是bug,是算法边界,千万记住。

那有人说了:我把每个回调扔到线程池里异步执行行不行?

行,但注意定时器回调里如果访问共享数据,锁竞争又成了新的瓶颈。

而且异步执行会打乱任务完成的时序——本来希望A任务在B之前完成,线程池一调度全乱了。所以HashedWheelTimer这类设计天生就只适合轻量、短平快的回调,比如设置一个标志位、发一个消息到队列。凡是涉及I/O或复杂计算的,统统交给专门的工作线程去做,时间轮只负责“闹钟响铃”这个动作。

官方文档也好,各路大牛的博客也好,都反复强调这种timer是approximated(近似)的,别指望准时。你要是非要毫秒级精度,把tickDurationMs设成1ms,那新问题又来了:tick频率太高,worker线程大部分时间在空转遍历大量空槽位,CPU先吃不消了。典型的精度和吞吐量不可兼得。

C++社区有没有更优雅的实现?

有。比如asio::steady_timer配合io_context,每个定时器独立管理,但那是基于最小堆的,不适合超大规模并发。还有基于timerfd+epoll驱动的轮子——这个我们后面会专门讲。

说了这么多,核心就一句话:HashedWheelTimer适合高吞吐、低精度的批量超时管理,别拿它当高精度定时器用

2.4 timerfd:用户态时间轮的终极方案

如果你在Linux用户空间手撸时间轮,最大的痛点是——谁来驱动这个轮子转?

以前很多人写Demo就这么写:

while (true) {    std::this_thread::sleep_for(std::chrono::milliseconds(10));    // 推进时间轮...}

看起来很自然对不对?

但如果服务跑在1000qps以上的生产环境里,sleep的精度和调度抖动会搞得你怀疑人生。我在排查第一次线上事故时才发现,std::this_thread::sleep_for底层依赖clock_nanosleep,它的实际唤醒时间受进程调度器的延迟影响,高负载下误差经常飙到几毫秒甚至几十毫秒。更致命的是,sleep线程哪怕什么都不干也在持续占用CPU做系统调用。这简直是“活着就已经给对方添麻烦了”的代码典范。

后来翻了大量资料,找到了最正统、最Linux式的方式:timerfd_create + epoll_wait

timerfd机制把定时器到期变成了文件描述符上的可读事件,直接融入epoll事件循环,完全避免轮询。

核心用法:

int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);struct itimerspec new_value;new_value.it_value.tv_sec = interval_sec;new_value.it_value.tv_nsec = interval_nsec;timerfd_settime(tfd, 0, &new_value, NULL);int epfd = epoll_create1(0);struct epoll_event ev;ev.events = EPOLLIN;ev.data.fd = tfd;epoll_ctl(epfd, EPOLL_CTL_ADD, tfd, &ev);while (true) {    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);    // tfd可读——定时器已到期    uint64_t expirations;    read(tfd, &expirations, sizeof(uint64_t));  // 必须读!清空到期次数    tick();  // 驱动时间轮推进}

定时器到期时,内核在定时器fd的内核缓冲区写入一个8字节的整数值,表示到期的次数。epoll检测到EPOLLIN时,必须调用read读走这8字节,否则内核会认为你不想清空,下次不会重新触发。

我手改那个网关方案时换了timerfd+epoll驱动后,定时器的调度精度从±20ms提升到±2ms以内,GC毛刺也大幅减少。关键是不再有一个线程在那里傻乎乎地sleep了——定时事件完全被epoll复用,线程数量原地降级。

但这个方案有个细节大家容易翻车:CLOCK_MONOTONIC。你如果用了CLOCK_REALTIME,NTP校准时系统时间往后或往前突变,绝对时间模式(TFD_TIMER_ABSTIME) 下任务可能永久丢失或瞬间全部触发。别问我怎么知道的╮(╯▽╰)╭。

三、手写一个简单的时间轮

懂了原理,咱们自己动手写一个简化版的时间轮。

假设:

  • 60 个槽

  • 每秒走一次

  • 支持秒级定时任务

3.1 数据结构

#include<iostream>#include<vector>#include<list>#include<functional>using namespace std;const int SLOT_NUM = 60;struct TimerTask {    int rotation;    int slot;    function<void()> callback;};class TimeWheel {private:    vector<list<TimerTask>> slots;    int current_slot;public:    TimeWheel() {        slots.resize(SLOT_NUM);        current_slot = 0;    }};

其实核心就两个东西:

  • 环形槽位

  • 当前指针

简单得有点不像高性能算法。

3.2 添加任务

voidadd_timer(int timeout, function<void()> cb) {    int ticks = timeout;    int rotation = ticks / SLOT_NUM;    int ts = (current_slot + (ticks % SLOT_NUM)) % SLOT_NUM;    TimerTask task;    task.rotation = rotation;    task.slot = ts;    task.callback = cb;    slots[ts].push_back(task);}

重点看:

rotation = ticks / SLOT_NUM

和:

slot = (current + offset) % SLOT_NUM

整个时间轮精髓就在这儿。

说白了,就是:

  • 算落哪个格子

  • 算还要转几圈

3.3 时间推进

voidtick(){    list<TimerTask> &lst = slots[current_slot];    for (auto it = lst.begin(); it != lst.end();) {        if (it->rotation > 0) {            it->rotation--;            ++it;        } else {            it->callback();            it = lst.erase(it);        }    }    current_slot = (current_slot + 1) % SLOT_NUM;}

这个 tick,就是整个时间轮发动机。

每秒调用一次。

然后:

  • 当前槽位任务 round--

  • round 为 0 的执行

  • 指针继续旋转

完事。

没有排序。

没有平衡树。

没有堆调整。

所以它非常快。

四、时间轮面试题

几道常考不衰的时间轮面试题

第一题:为什么时间轮里每个槽都要用双向链表?

有的人愣半天,说“因为方便遍历”。双向链表的本事在于——它能以O(1)的代价从中间任意位置删除或取消节点。假设定时任务支持cancel()操作,没有双向指针的链表只能从头找到尾才能删除。单层桶里几百个任务一挂,删除一次就是O(n),这谁受得了。在多级时间轮里,跨级迁移和删除尤其需要双向链表的随机删除能力。

第二题:多级时间轮的级联机制如果某槽内有百万任务,会有什么问题?

这里通常没人想过。其实当某层的某个槽里有海量定时器时,触发cascade的那一次tick会一次性转移全部百万个任务到下一级,导致该次tick的CPU耗时飙高,后续所有调度都跟着延迟。这不是算法崩溃,而是延迟尖刺。解决方案:如果业务特征里确实可能聚集到百万个任务同时落在同一槽,可以考虑在高层级槽使用延迟队列加分批迁移的策略,而不是一次性全搬。

第三题:epoll_wait的timeout参数可以替代时间轮吗?

这是老有人偷懒的“骚操作”——epoll_wait(epfd, events, MAX_EVENTS, 100)直接当定时器用。但epoll的超时精度最差能到1ms级,且它的设计目标是等待I/O事件,不是管理大量并发定时器。你怎么给上万个连接设各自不同的超时?定时器链表里还得额外维护到期时间,对epoll_timeout来说是做不到的。所以时间轮的核心价值在于:管理大量独立超时源的O(1)能力,epoll_timeout做不到这一点。

第四题:Redis 为什么没直接用时间轮?

很多面试官会问,Redis有大量过期key,为什么不用时间轮?因为Redis场景不同。Redis key过期时间跨度太随机,而且数量巨大、时间分布离散、精度要求不高。于是Redis采用惰性删除加定期随机扫描。本质上,它在空间和CPU之间找了平衡。所以技术方案永远没有银弹,一定是场景驱动。别看到一个新技术就想everywhere。

第五题:为什么很多公司最后还是不用时间轮?

因为很多文章会让你误以为“时间轮天下无敌”,其实并不是。时间轮有几个硬伤:精度有限——tick越大误差越大,tick越小CPU开销越大,这是天然的tradeoff。不适合超高精度场景,比如高频交易、实时控制、音视频同步,这些更偏向hrtimer。超长延迟管理复杂——虽然多层时间轮能解决,但实现复杂度会上升,而且cascade本身也有成本。调试困难,这点特别真实。线上timer出问题时,你会发现根本不知道它在哪层、哪一圈、什么时候触发,日志都不好打。

五、什么时候千万别用时间轮

时间轮,优雅,高效,但一定要锚定场景。

你拿它做双11秒杀的延迟库存释放集群没问题。拿它做证券交易中价位和波动率依赖的精准调度,一个100ms的偏差就能让策略模型直接失效。精度不够就是精度不够,算法再美也得选对场景。

Linux内核为什么时间轮和高精度定时器红黑树同时存在?因为它们服务的精度域不同——时间轮面向高吞吐、批量粗粒度的定时任务;hrtimer面向低延迟、纳秒级精度要求。你需要知道自己面对的是哪类问题。

这几年代码从多级轮子改到timerqueue,又改到基于timerfd的多级离散版本,我发现一个规律——写代码总是在“整洁的抽象”和“残酷的现实”之间反复摩擦。10ms的精度差别也许在代码里只是一行的差异,在业务上可能是一个重度游戏玩家的暴怒退游。所以,永远不要被算法的美迷惑了双眼,扎实用好tickDuration、慎用绝对时间模式,并且——务必把监控配起来。监控tick间隔偏离、pending timeout的数量、cascade耗时这些指标,别等到线上崩了再去补。

六、避坑点

坑 1:时间精度问题

系统时钟滴答的精度影响时间轮精度。如果滴答是 10 毫秒,那你设置的 5 毫秒定时器肯定不准。我们之前有个实时监控任务,要求 1 毫秒精度,结果发现系统滴答是 10 毫秒,只能手动修改内核配置,把 HZ 从 100 调到 1000,这才搞定。

坑 2:定时器过期处理

如果任务执行时间超过到期时间,比如定时器 A 应该在 10:00:00 触发,但执行到 10:00:05 才完成,那后面的定时器就全乱套了!我们当时的解决办法是:任务执行时,先检查当前时间是否已经过了下一个到期点,如果过了就重新入队,确保不会积压。

坑 3:高并发下的锁竞争

在多线程环境下,添加和删除定时器需要加锁。但锁太粗会导致性能暴跌。我们后来用了细粒度锁,给每个时间轮槽位加独立的锁,把性能提升了 5 倍!

坑 4:内存管理陷阱

大量创建和删除定时器会导致内存碎片。我们曾经遇到过系统运行几天后,内存碎片率飙升到 90%,最后改用内存池(比如 tcmalloc)才解决。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 23:14:21 HTTP/2.0 GET : https://f.mffb.com.cn/a/492511.html
  2. 运行时间 : 0.091728s [ 吞吐率:10.90req/s ] 内存消耗:4,566.77kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=4e685b4da798f0e33815df9ed5935140
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000618s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000766s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000352s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000300s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000792s ]
  6. SELECT * FROM `set` [ RunTime:0.000287s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000659s ]
  8. SELECT * FROM `article` WHERE `id` = 492511 LIMIT 1 [ RunTime:0.000584s ]
  9. UPDATE `article` SET `lasttime` = 1783091661 WHERE `id` = 492511 [ RunTime:0.009459s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000247s ]
  11. SELECT * FROM `article` WHERE `id` < 492511 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000447s ]
  12. SELECT * FROM `article` WHERE `id` > 492511 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001470s ]
  13. SELECT * FROM `article` WHERE `id` < 492511 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000622s ]
  14. SELECT * FROM `article` WHERE `id` < 492511 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001328s ]
  15. SELECT * FROM `article` WHERE `id` < 492511 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000815s ]
0.093317s