当前位置:首页>学习笔记>brpc 学习笔记(十四):ParkingLot——worker 线程的停泊与唤醒

brpc 学习笔记(十四):ParkingLot——worker 线程的停泊与唤醒

  • 2026-05-18 07:22:30
brpc 学习笔记(十四):ParkingLot——worker 线程的停泊与唤醒

摘要:前文拆解了TaskGroup的调度机制。本文分析其底层同步原语ParkingLot——基于futex实现worker线程的高效挂起与唤醒。_pending_signal低位编码stop标志与信号计数,State快照实现check-then-wait一致性,_no_signal_when_no_waiter在繁忙时跳过futex_wake减少系统调用。

在上一篇文章中,我们拆解了 TaskGroup——bthread 调度的核心单元。我们看到 worker pthread 在没有任务时通过 wait_task 进入等待,被唤醒后从队列中窃取任务执行。

这个"等待/唤醒"机制的底层实现就是 ParkingLot

bthread 的 M:N 模型中,worker pthread 是稀缺资源。当没有就绪的 bthread 时,worker 需要被挂起以节省 CPU;当新任务到来时,需要唤醒足够数量的 worker 来处理。ParkingLot 就是管理这个"停泊/唤醒"机制的核心同步原语——名字取自"停车场"的比喻:worker 是车,ParkingLot 是停车场,空转的 worker 在这里"停放",有任务时再"驶出"。


一、ParkingLot 概览

                   TaskControl                  ┌────────────────────────────────┐                  │  ParkingLot[0]  ←── worker 0   │                  │  ParkingLot[1]  ←── worker 1   │                  │  ...                           │                  │  ParkingLot[N-1] ←── worker N-1                  └────────────────────────────────┘  worker 0 的视角:  ┌──────────┐    get_state()     ┌──────────────┐  │ worker 0 │ ──────────────────→│ ParkingLot[0] │  │          │    wait(state)     │              │  │          │ ──────────────────→│ futex_wait   │  │          │                    │              │  │          │ ←──────────────────│ futex_wake   │  │ (唤醒)   │    signal(n)      │              │  └──────────┘                    └──────────────┘       ↑                                ↑       │         调度器提交任务           │       └──── signal(num_task) ──────────┘

每个 worker pthread 对应一个 ParkingLot 实例。worker 通过 get_state() + wait() 在 ParkingLot 上等待,调度器通过 signal() 唤醒指定数量的 worker。这种一对一的关系简化了唤醒逻辑——每个 worker 有自己专属的"停车位"。

ParkingLot 基于 Linux futex(fast userspace mutex)实现。futex 的核心思想:在用户态快速检查条件,仅在需要等待时才陷入内核。这避免了传统信号量/条件变量在无竞争场景下的系统调用开销。


二、数据结构

classBAIDU_CACHEIN_ALIGNMENTParkingLot{public:    classState{    public:        State(): val(0) {}        bool stopped() const { return val & 1; }  // LSB = stop 标志    private:    friend classParkingLot;        State(int val) : val(val) {}        int val;                                    // _pending_signal 的快照    };private:    butil::atomic<int> _pending_signal;             // 信号 + stop 标志    butil::atomic<int> _waiter_num;                 // 等待者计数    bool _no_signal_when_no_waiter;                 // 无等待者时跳过 signal};

ParkingLot 只有三个成员变量,结构精简:

2.1 _pending_signal:编码信号与停止标志

_pending_signal 是一个 32 位原子整数,编码了两种信息:

  31                              1  0  ┌───────────────────────────────┬───┐  │        信号计数 (signal)       │ S │  └───────────────────────────────┴───┘  高 31 位:每次 signal 增加的计数     LSB:stop 标志  每次signal(num_task) += num_task << 1  0=正常  1=已停止
  • bit 0(LSB):stop 标志。stop() 将其置 1,表示 ParkingLot 已停止服务
  • bit 1~31:信号计数。每次 signal(num_task) 执行 fetch_add(num_task << 1),将 num_task 左移一位后加到高 31 位

为什么用 num_task << 1 而不是直接加 num_task?因为 LSB 被 stop 标志占用,左移一位确保不干扰 stop 位。这种编码让一个原子变量同时承载两种信息,且操作互不干扰——signal 只修改高位,stop 只修改低位。

2.2 _waiter_num:等待者计数

当前在此 ParkingLot 上等待(即调用了 futex_wait)的 worker 数量。仅在 _no_signal_when_no_waiter 启用时才有实际意义——用于在所有 worker 都繁忙时跳过不必要的 futex_wake

2.3 _no_signal_when_no_waiter:无等待者优化

从 gflags FLAGS_parking_lot_no_signal_when_no_waiter 读取,默认值取决于编译配置。启用后,当没有 worker 在等待时,signal() 跳过 futex_wake 系统调用。

这个优化针对的是所有 worker 都在处理任务的繁忙场景:此时 futex_wake 唤醒不了任何人(没有人在等),白白执行了一次系统调用。

2.4 State:状态快照

State 是 _pending_signal 的只读快照。它只有一个 val 字段和一个 stopped() 方法。State 的核心价值在于实现 check-then-wait 的一致性——下一节详述。

注意 BAIDU_CACHEIN_ALIGNMENT:ParkingLot 被对齐到缓存行(64 字节),避免不同 ParkingLot 实例之间的 false sharing。每个 worker 频繁读写自己的 ParkingLot,缓存行隔离确保不会互相干扰。


三、signal:唤醒 worker

int signal(int num_task) {    // 1. 增加信号计数(高 31 位)    _pending_signal.fetch_add((num_task << 1), butil::memory_order_release);    // 2. 检查是否有等待者    if(_no_signal_when_no_waiter &&        _waiter_num.load(butil::memory_order_relaxed) == 0) {        return 0;  // 无等待者,跳过 futex_wake    }    // 3. 唤醒最多 num_task 个等待者    return futex_wake_private(&_pending_signal, num_task);}

三步操作:

步骤 1:增加信号计数。fetch_add(num_task << 1) 原子地修改 _pending_signal 的高 31 位。即使步骤 3 的 futex_wake 被跳过,信号计数的增加也已经发生——后续的 wait() 会通过 State 快照检测到变化。

步骤 2:检查等待者。 如果启用了 _no_signal_when_no_waiter 且当前没有等待者,直接返回 0。使用 memory_order_relaxed 读取 _waiter_num——这里的判断是乐观的:即使 _waiter_num 即将变为非零(某个 worker 正准备等待),也不会造成正确性问题,只是本次 signal 没有唤醒,该 worker 等待后会正常醒来(因为信号计数已增加)。

步骤 3:唤醒等待者。futex_wake_private 是 Linux futex 系统调用的封装,唤醒在 _pending_signal 上等待的最多 num_task 个线程。返回实际唤醒的线程数。

关键设计:先修改信号计数,再决定是否唤醒。即使跳过了 futex_wake,信号计数的变化也被记录——后续 worker 的 wait() 检测到不匹配时不会阻塞。


四、get_state 与 wait:等待任务

State get_state() {    return _pending_signal.load(butil::memory_order_acquire);}

返回当前 _pending_signal 的快照。worker 在 wait() 之前先调用 get_state() 保存当前状态,用于后续的一致性检查。

4.2 wait:挂起 worker

void wait(const State& expected_state) {    // 1. 快速路径:检查状态是否已变化    if(get_state().val != expected_state.val) {        return;  // 已有新信号,不需要等待    }    // 2. 增加等待者计数    if(_no_signal_when_no_waiter) {        _waiter_num.fetch_add(1, butil::memory_order_relaxed);    }    // 3. 阻塞等待    futex_wait_private(&_pending_signal, expected_state.val, NULL);    // 4. 减少等待者计数    if(_no_signal_when_no_waiter) {        _waiter_num.fetch_sub(1, butil::memory_order_relaxed);    }}

四步操作:

步骤 1:快速路径检查。 重新读取 _pending_signal 并与 expected_state 比较。如果不相等,说明在 get_state() 和 wait() 之间有 signal() 发生过——新任务已经到来,不需要等待,直接返回。

这是 futex 的经典用法:用户态快速检查 + 内核态等待。在没有竞争的常见场景下,信号在 worker 开始等待之前就到了,此时快速路径命中,完全不需要系统调用。

步骤 2:增加等待者计数。 如果启用了 _no_signal_when_no_waiter,在进入等待前递增 _waiter_num,让 signal() 知道有人在等待。

步骤 3:futex 等待。futex_wait_private(&_pending_signal, expected_state.val, NULL) 调用 futex 系统调用。内核会比较 _pending_signal 的当前值与 expected_state.val

  • 如果相等:阻塞当前线程,直到 futex_wake 唤醒
  • 如果不等:立即返回(EAGAIN),说明在步骤 1 和步骤 3 之间有 signal 发生

步骤 1 的用户态检查 + 步骤 3 的内核态检查构成双重检查:即使在步骤 1 通过后、步骤 3 执行前有 signal 发生,futex 的内核态检查也能捕获这个变化。

步骤 4:减少等待者计数。 等待结束(被唤醒或假唤醒)后递减 _waiter_num

4.3 State 快照的一致性保证

  worker 视角:                           signal 视角:  get_state() ─→ state=S0                                        fetch_add(2)  → _pending_signal=S0+2                                        futex_wake(1)  wait(S0):    检查 S0 != S0+2 → 不等 → 直接返回!
如果没有 State 快照机制,worker 可能错过信号:
  无快照的情况(假设直接 wait):  wait():    futex_wait(&_pending_signal, 当前值)    ← 如果 signal 在读取当前值和 futex_wait 之间发生 → 丢失唤醒!

State 快照将"读取期望值"和"传入期望值"分离到两个调用中,中间的窗口由 futex 内核的原子比较来弥合。这是 wait/wake 模式的标准实践。


五、stop:停止服务

void stop() {    // 1. 设置 stop 标志(LSB 置 1)    _pending_signal.fetch_or(1);    // 2. 唤醒所有等待者    futex_wake_private(&_pending_signal, 10000);}

stop() 在程序退出时调用(TaskControl::stop_and_join),通知所有 worker 停止工作。

两步操作:

步骤 1:设置 stop 标志。fetch_or(1) 原子地将 _pending_signal 的最低位置 1。这同时改变了 _pending_signal 的值——正在 futex_wait 的 worker 会因为值不匹配而被唤醒。

步骤 2:唤醒所有等待者。 传入 10000 是一个足够大的值,确保所有在此 ParkingLot 上等待的 worker 都被唤醒。

唤醒后,worker 在 wait_task 中检查 _last_pl_state.stopped() 返回 true,主循环 run_main_task 退出。


六、在 TaskControl 中的集成

ParkingLot 在 TaskControl 中被创建和管理:
classTaskControl{    // 通常与 worker 数量相同    ParkingLot* _pl;                    // ParkingLot 数组};
每个 worker pthread 在 TaskControl::add_worker 中被分配一个 ParkingLot:
  worker 0  ←→  _pl[0]  worker 1  ←→  _pl[1]  ...  worker N  ←→  _pl[N]

6.1 worker 等待流程

// TaskGroup::wait_task (简化)boolTaskGroup::wait_task(bthread_t* tid){    do {        if (_last_pl_state.stopped()) return false;    // stop 检查        _pl->wait(_last_pl_state);                     // 在 ParkingLot 上等待        _last_pl_state = _pl->get_state();             // 更新快照        if (steal_task(tid)) return true;              // 窃取任务    } while (true);}

worker 等待后更新 _last_pl_state——确保下次 wait() 使用最新的快照,避免重复唤醒。

6.2 调度器唤醒流程

// TaskControl::signal_task (简化)voidTaskControl::signal_task(int num_task, bthread_tag_t tag){    // 遍历 ParkingLot,唤醒 num_task 个 worker    for (int i = 0; i < _options.num_workers; ++i) {        int wake = _pl[idx].signal(num_task);        num_task -= wake;        if (num_task <= 0break;    }}

调度器遍历 ParkingLot 数组,依次唤醒 worker,直到满足所需数量。唤醒成功(signal 返回 > 0)时递减剩余需求,所有需求满足后停止遍历。


七、_no_signal_when_no_waiter 优化详解

这个优化值得单独分析,因为它体现了 bthread 对实际工作负载的细致考量。

7.1 问题:繁忙场景下的无效唤醒

  场景:8 个 worker 全部在执行 bthread  worker 0: [执行任务 A] ← 繁忙  worker 1: [执行任务 B] ← 繁忙  ...  worker 7: [执行任务 G] ← 繁忙  此时 signal(3) 到来:  - 没有任何一个 worker 在 ParkingLot 上等待  - futex_wake(&_pending_signal, 3) → 返回 0(唤醒了 0 个线程)  - 但系统调用开销仍然存在

在高负载场景下,worker 大部分时间都在执行任务,很少在 ParkingLot 上等待。每次 signal_task 都调用 futex_wake,但几乎总是返回 0。系统调用的开销虽然不大(通常 < 1μs),但在高频调度场景下会累积。

7.2 解决方案:条件唤醒

启用 _no_signal_when_no_waiter 后:

  signal(3):    fetch_add(6)           → 信号计数增加(始终执行)    _waiter_num == 0 ?     → 是 → 跳过 futex_wake,返回 0

信号计数始终增加——即使跳过了 futex_wake,当 worker 完成当前任务回到 wait_task 时,State 快照不匹配会命中快速路径,worker 不会阻塞,直接尝试窃取新任务。

7.3 正确性保证

可能担心一个竞态场景:signal() 检查 _waiter_num 时为 0,但 wait() 随后增加了 _waiter_num

  signal():                    wait():  fetch_add(6)  _waiter_num == 0 → true                               _waiter_num.fetch_add(1)  → 变为 1                               futex_wait(&signal, S0)   → S0+6 ≠ S0 → 立即返回  跳过 futex_wake              被 futex_wait 快速路径唤醒

即使 signal() 跳过了 futex_wakewait() 中的 futex_wait_private 会检测到 _pending_signal 的值(S0+6)与 expected_state.val(S0)不匹配,立即返回 EAGAIN。futex 的内核态比较是最后一道安全网

_waiter_num 使用 memory_order_relaxed 也是安全的——它只是一个提示,不参与同步。最坏情况是多一次不必要的 futex_wake,不会导致丢失唤醒。


八、与 TaskGroup 的协作时序

完整的 worker 生命周期中,ParkingLot 的调用时序:

  run_main_task():    while (wait_task(&tid)) {       ←── 外层循环      sched_to(&dummy, tid);        ←── 执行 bthread    }  wait_task():    loop:      _last_pl_state.stopped()?     ←── 检查 stop        return false      _pl->wait(_last_pl_state)     ←── ParkingLot.wait()      _last_pl_state = get_state()  ←── 更新快照      steal_task(tid)?              ←── 尝试窃取        return true      goto loop                     ←── 窃取失败,重新等待

关键观察:

1. wait 之前必须先 get_state。wait_task 在循环中先检查 stopped(),再调用 wait()_last_pl_state 在上一次循环中通过 get_state() 更新。

2. wait 返回后立即更新快照。 避免下次 wait 使用过期状态。

3. 窃取失败后重新等待。 假唤醒(spurious wakeup)或被其他 worker 抢先窃取时,worker 会回到 ParkingLot 重新等待。


九、futex 基础

ParkingLot 的实现基于 Linux futex 系统调用。理解 futex 有助于理解 ParkingLot 的设计:
// futex_wait:如果 *uaddr == val,则阻塞当前线程intfutex_wait_private(int* uaddr, int val, const timespec* timeout);// futex_wake:唤醒最多 count 个在 *uaddr 上等待的线程intfutex_wake_private(int* uaddr, int count);

futex 的核心优势:

  • 用户态快速路径
    :先在用户态检查条件(get_state().val != expected_state.val),条件不满足时直接返回,不需要系统调用
  • 内核态等待
    :仅在需要阻塞时才陷入内核,避免了传统条件变量的互斥锁开销
  • 精确唤醒
    futex_wake 可以精确控制唤醒的线程数量,而不是广播唤醒所有等待者

ParkingLot 使用的 futex_wait_private / futex_wake_private 是 FUTEX_WAIT_PRIVATE / FUTEX_WAKE_PRIVATE 的封装——它们要求等待和唤醒在同一个进程内,避免了跨进程的开销。


十、总结

ParkingLot 的设计可以归纳为一句话:基于 futex 的轻量级同步原语,一个原子变量编码信号计数与停止标志,State 快照确保 check-then-wait 一致性,_no_signal_when_no_waiter 优化繁忙场景

四个关键设计:

1. _pending_signal 的位编码。 一个 32 位原子变量同时承载两种信息:高 31 位是信号计数(每次 signal 增加 num_task << 1),LSB 是停止标志。两种操作互不干扰——signal 修改高位,stop 修改低位。编码方式简洁高效。

2. State 快照 + 双重检查。 worker 先 get_state() 获取快照,再 wait(expected_state) 等待。wait 中有两次检查:用户态比较(快速路径)和 futex 内核态比较(慢速路径)。双重检查确保不会丢失唤醒信号。

3. _no_signal_when_no_waiter 条件唤醒。 繁忙场景下所有 worker 都在执行任务,futex_wake 只会白白执行系统调用。通过 _waiter_num 检查是否有等待者,没有则跳过唤醒。信号计数始终增加,确保 worker 回到等待时能检测到变化。

4. 缓存行对齐。BAIDU_CACHEIN_ALIGNMENT 确保每个 ParkingLot 独占一个缓存行。每个 worker 频繁读写自己的 ParkingLot 的 _pending_signal 和 _waiter_num,缓存行隔离消除 false sharing。

ParkingLot 虽然代码不到 100 行,但每个设计细节都有明确的性能或正确性考量。它是 bthread 调度系统的"齿轮"——小而精密,连接着 TaskGroup 的调度循环和操作系统的 futex 机制。


本文基于 Apache brpc 源码(src/bthread/parking_lot.h)撰写。

最新文章

随机文章

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