当前位置:首页>学习笔记>brpc 学习笔记(八):bthread_sem_t——协程友好的信号量

brpc 学习笔记(八):bthread_sem_t——协程友好的信号量

  • 2026-05-06 22:21:52
brpc 学习笔记(八):bthread_sem_t——协程友好的信号量
摘要:上一篇文章拆解了 bthread_cond_t 的实现——用序列号 butex 实现 wait/signal/broadcast 语义,用 butex_requeue 优化广播性能。本文继续拆解另一个基于 butex 的同步原语:信号量 bthread_sem_t。与互斥锁的二态(锁/未锁)和条件变量的等待/通知模式不同,信号量的核心是"计数"——butex 的值直接就是信号量的计数值。trywait 用 CAS 原子递减,wait 在计数为零时通过 butex_wait 挂起,post 用 fetch_add 原子递增并通过 butex_wake_n 唤醒等待者。此外,bthread 独有的 post_n 批量操作和内置的竞争分析能力也是值得关注的亮点。

在上一篇文章中,我们拆解了 bthread_cond_t——协程友好的条件变量。我们看到它用一个序列号 butex 实现 wait/signal/broadcast 语义,用 butex_requeue 优化广播性能,避免惊群效应。

现在我们继续拆解另一个基于 butex 的同步原语:信号量

信号量与互斥锁、条件变量都不同。互斥锁只有两个状态(锁/未锁),条件变量是纯粹的等待/通知机制,而信号量的核心是计数——一个非负整数,表示可用资源的数量。P 操作(wait)递减计数,计数为零时阻塞;V 操作(post)递增计数,唤醒等待者。

bthread 的信号量是如何基于 butex 实现这种"计数"语义的?让我们从数据结构开始。


一、bthread_sem_t:butex 就是计数器

typedef struct bthread_sem_t {    unsigned* butex;     // butex 指针,值就是信号量计数值    bool enable_csite;   // 是否启用竞争统计bthread_sem_t;

与互斥锁和条件变量都不同,信号量的 butex 值直接就是信号量的计数,不需要额外的编码或拆分:

butex 值
含义
0
无可用资源,wait 会阻塞
> 0
有 N 个可用资源,wait 可以立即获取

这使得信号量的实现比互斥锁更直观——不需要 MutexInternal 那样的位拆分,也不需要条件变量的序列号。butex 的值就是业务含义本身。

enable_csite 控制竞争分析采样(与互斥锁的 enable_csite 相同),默认启用。


二、初始化与销毁

2.1 bthread_sem_init

intbthread_sem_init(bthread_sem_t* sem, unsigned value){    sem->butex = bthread::butex_create_checked<unsigned>();    if (!sem->butex) {        return ENOMEM;    }    *sem->butex = value;    sem->enable_csite = true;    return 0;}

从 ObjectPool 分配一个 butex(参见本系列第四篇),设置初始计数值 value。与 pthread_sem_init 的区别:不支持进程共享(无 pshared 参数),因为 butex 是进程内私有的。

2.2 bthread_sem_destroy

intbthread_sem_destroy(bthread_sem_t* semaphore){    bthread::butex_destroy(semaphore->butex);    return 0;}

归还 butex 到 ObjectPool。与所有 butex 用户一样,butex_destroy 和 butex_wake 之间存在竞态,ObjectPool 的"永不释放"特性保证了安全。


三、trywait:非阻塞获取

staticinlineintbthread_sem_trywait(bthread_sem_t* sema){    auto whole = (butil::atomic<unsigned>*)sema->butex;    while (true) {        unsigned num = whole->load(butil::memory_order_relaxed);        if (num == 0) {            return EAGAIN;   // 计数为 0,无法获取        }        if (whole->compare_exchange_weak(num, num - 1,                                         butil::memory_order_acquire,                                         butil::memory_order_relaxed)) {            return 0;        // CAS 成功,计数减 1        }        // CAS 失败(num 被其他线程改了),重试    }}
trywait 是信号量的"快速路径"——不阻塞,只尝试获取。实现是一个 CAS 循环:
load(num) → num == 0? → 返回 EAGAIN          → num > 0?  → CAS(num, num-1)                        → 成功:返回 0                        → 失败:重试

为什么用 CAS 而不是互斥锁中的 exchange? 这是一个关键的设计选择。

互斥锁的 exchange(CONTENDED=3) 是独占操作——"原子地标记为已占用",不需要先检查值。信号量则不同:它是共享的(多个线程可以同时持有),必须"先读 → 判断 > 0 → 再减",需要 CAS 的两步语义。CAS 的 compare 步骤确保了"判断 > 0"和"减 1"是原子的——中间不会被其他线程抢先减到负数。

使用 compare_exchange_weak 而非 strong 是性能考虑:在某些架构上 weak 更高效,而循环中 weak 的虚假失败只是多一次重试,不影响正确性。


四、wait:阻塞获取

staticintbthread_sem_wait_impl(bthread_sem_t* sem, conststruct timespec* abstime){    bool queue_lifo = false;    bool first_wait = true;    // ...    auto whole = (butil::atomic<unsigned>*)sem->butex;    while (true) {        unsigned num = whole->load(butil::memory_order_relaxed);        if (num > 0) {            if (whole->compare_exchange_weak(num, num - 1,                                             butil::memory_order_acquire,                                             butil::memory_order_relaxed)) {                return 0;    // CAS 成功,获取信号量            }            continue;       // CAS 失败,重试        }        // num == 0,需要等待        if (bthread::butex_wait(sem->butex, 0, abstime, queue_lifo) < 0 &&            errno != EWOULDBLOCK && errno != EINTR) {            return errno;   // 超时或错误        }        // EWOULDBLOCK:值已经不是 0(被 post 了),重试        // EINTR:被中断,重试        if (first_wait && 0 == errno) {            first_wait = false;        }        if (!first_wait) {            queue_lifo = true;  // 被唤醒后下次插队(LIFO 防饥饿)        }    }}

wait 是信号量的核心操作。与 trywait 相比,多了一个阻塞等待的分支。整体是一个循环,每轮尝试两件事:

4.1 快速路径:CAS 获取

unsigned num = whole->load(butil::memory_order_relaxed);if (num > 0) {    if (whole->compare_exchange_weak(num, num - 1, ...)) {        return 0;  // 成功    }    continue;      // CAS 失败,重试}

与 trywait 完全相同的 CAS 逻辑。如果计数 > 0 且 CAS 成功,直接获取信号量。

4.2 慢速路径:butex_wait

if (bthread::butex_wait(sem->butex, 0, abstime, queue_lifo) < 0 &&    errno != EWOULDBLOCK && errno != EINTR) {    return errno;}

当计数为 0 时,调用 butex_wait(butex, 0, ...) ——期望值为 0,表示"当 butex 仍然是 0 时就等待"。如果 butex 值已经被 post 改变(不再是 0),butex_wait 立即返回 EWOULDBLOCK,循环继续,下一轮 CAS 可能成功。

4.3 FIFO → LIFO 防饥饿策略

if (first_wait && 0 == errno) {    first_wait = false;}if (!first_wait) {    queue_lifo = true;}

这与互斥锁的策略完全相同(参见本系列第六篇):

  • 第一次等待:FIFO(排到队尾)
    ——公平地与其他等待者竞争
  • 被唤醒后再次等待:LIFO(插到队头)
    ——被唤醒的 bthread 需要与新到达的 bthread 竞争信号量。新到达者已经在 CPU 上运行,有巨大优势。LIFO 插队给被唤醒者更高的优先级,避免被反复"抢跑"导致饥饿

4.4 完整流程图

wait()┌──────────────────────────────────────────┐│ load(num)                                ││ num > 0?                                 ││   Yes → CAS(num, num-1)                  ││          → 成功:return 0                 ││          → 失败:continue                 ││   No  → butex_wait(butex, 0)             ││          → EWOULDBLOCK: continue(值变了)││          → 被唤醒: continue(重新 CAS)   ││          → ETIMEDOUT: return errno        │└──────────────────────────────────────────┘

关键观察:wait 的循环天然处理了虚假唤醒。 被唤醒后不会假设自己拿到了信号量,而是回到循环顶部重新 load + CAS。这比条件变量的"必须用 while 循环"更自然——信号量的循环本身就是标准用法。


五、post:释放信号量

staticinlineintbthread_sem_post(bthread_sem_t* sem, size_t num){    if (num > 0) {        unsigned n = ((butil::atomic<unsigned>*)sem->butex)            ->fetch_add(num, butil::memory_order_relaxed);        bthread::butex_wake_n(sem->butex, n);    }    return 0;}

post 只需两步:fetch_add 递增计数 + butex_wake_n 唤醒等待者

5.1 fetch_add:原子递增

unsigned n = ((butil::atomic<unsigned>*)sem->butex)    ->fetch_add(num, butil::memory_order_relaxed);

fetch_add 返回旧值n,同时将计数增加 num。这个旧值 n 决定了唤醒策略。

5.2 butex_wake_n:按旧值唤醒

bthread::butex_wake_n(sem->butex, n);

butex_wake_n 的语义:最多唤醒 n 个等待者。但 n 是 post 前的旧值:

  • n == 0
    :post 前计数为 0,可能有等待者。butex_wake_n(butex, 0) 会唤醒所有等待者
  • n > 0
    :post 前计数已大于 0,可能没有等待者。butex_wake_n(butex, n) 最多唤醒 n 个(如果没有等待者,什么也不做)

5.3 为什么 n==0 时唤醒所有?

这是一个容易混淆的设计。考虑一个例子:

初始:butex = 03 个等待者在 butex_wait(0) 上挂起post(sem, 2):    n = fetch_add(2) → n = 0(旧值)    butex 变成 2    butex_wake_n(butex, 0) → 唤醒所有等待者(3 个)3 个等待者都被唤醒后,在 CAS 循环中竞争:    等待者 A: CAS(21) 成功,获取信号量    等待者 B: CAS(10) 成功,获取信号量    等待者 C: CAS(0→?) 失败,回到 butex_wait 继续等待

唤醒所有等待者 ≠ 所有等待者都能获取信号量。butex_wake_n 的作用是"打破挂起状态",让等待者有机会竞争。 多余的等待者在 CAS 循环中失败后会重新挂起。这是正确的——最多 num(本例中为 2)个等待者能成功获取信号量。

从另一个角度看:如果 n > 0(post 前已有资源),说明当时没有等待者(否则它们早就获取了),所以 butex_wake_n(butex, n) 唤醒 0 个是正确的。

5.4 post_n:批量释放

intbthread_sem_post_n(bthread_sem_t* sem, size_t n){    return bthread::bthread_sem_post(sem, n);}

bthread 独有的功能——标准 POSIX 信号量没有等价操作。一次增加 n 个计数,然后按旧值唤醒等待者。典型场景:生产者一次生产多个资源,一次性通知所有等待者。

普通的 bthread_sem_post 是 post_n 的特例:

intbthread_sem_post(bthread_sem_t* sem){    return bthread::bthread_sem_post(sem, 1);}

六、竞争分析(Contention Profiling)

与互斥锁(本系列第六篇)一样,信号量内置了竞争分析能力。关键代码在 wait_impl 中:

// 等待开始时采样if (NULL != bthread::g_cp && start_ns == 0 && sem->enable_csite &&    !bvar::is_sampling_range_valid(sampling_range)) {    sampling_range = bvar::is_collectable(&bthread::g_cp_sl);    start_ns = bvar::is_sampling_range_valid(sampling_range) ?               butil::cpuwide_time_ns() : -1;}// 获取成功后提交采样if (start_ns > 0) {    const int64_t end_ns = butil::cpuwide_time_ns();    const bthread_contention_site_t csite{end_ns - start_ns, sampling_range};    bthread::submit_contention(csite, end_ns);}

工作流程:

  1. 进入竞争路径时(CAS 失败或计数为 0),检查竞争分析器是否启动
  2. 如果启动且需要采样,记录等待开始时间
  3. 获取信号量成功后,计算等待时间并提交采样
  4. 超时也会提交采样(记录等待了多长时间后放弃)

bthread_sem_disable_csite 可以关闭单个信号量的竞争统计:

intbthread_sem_disable_csite(bthread_sem_t* sema){    sema->enable_csite = false;    return 0;}

七、信号量 vs 互斥锁 vs 条件变量

三种同步原语都基于 butex,但设计思路各有不同:

bthread_mutex_t
bthread_cond_t
bthread_sem_t
butex 用途
状态编码(0/1/3)
序列号(递增通知)
计数值(资源数量)
核心操作
exchange(独占)
fetch_add + butex_wake/requeue
CAS(共享) + fetch_add
等待条件
但ex == CONTENDED
但ex == expected_seq
但ex == 0
唤醒方式
butex_wake(1个)
signal: butex_wake; broadcast: butex_requeue
butex_wake_n(按旧值)
持有概念
有(锁持有者)
无(通知关系)
无(计数消费)

关键区别在于 butex 值的语义:

  • 互斥锁
    :butex 值是编码后的状态(0/1/3),用 exchange 实现"设状态 + 检查旧状态"的原子操作
  • 条件变量
    :butex 值是序列号,每次通知递增,等待者通过比较序列号判断是否被通知
  • 信号量
    :butex 值直接就是计数值,用 CAS 实现原子递减,用 fetch_add 实现原子递增

信号量是三者中最"直接"的——butex 值就是业务含义本身,不需要额外的编码层。


八、与 pthread 信号量的对比

sem_t (POSIX)
bthread_sem_t
进程共享
支持(pshared)
不支持(butex 是进程内私有的)
阻塞方式
futex 系统调用
butex_wait(bthread 让出 CPU)
trywait
sem_trywait
bthread_sem_trywait(CAS 循环)
批量 post
不支持
bthread_sem_post_n(独有)
竞争分析
不支持
内置(enable_csite)
混合使用
仅 pthread
bthread/pthread 可互相同步

最后一点是 bthread 同步原语的共同优势:同一个信号量上,bthread 和 pthread 可以互相 wait/post。底层 butex 的 ButexWaiter 通过 tid 区分等待者类型(参见本系列第四篇),唤醒时按类型分发。


九、总结

bthread_sem_t 的设计可以归纳为一句话:butex 的值就是信号量的计数值,用 CAS 消费、fetch_add 生产、butex_wait 阻塞、butex_wake_n 唤醒

四个关键设计:

1. butex 即计数器。 与互斥锁的位拆分和条件变量的序列号不同,信号量的 butex 值直接就是计数值。这使得实现最直观——读值就是读计数,CAS(num, num-1) 就是获取资源,fetch_add(n) 就是释放资源。

2. CAS 循环 + butex_wait 的组合。 wait 操作在一个循环中交替尝试 CAS 获取和 butex_wait 等待。CAS 失败或计数为零时进入 butex_wait;被唤醒后不假设成功,回到循环顶部重新尝试。这种"乐观尝试 → 悲观等待 → 重新乐观尝试"的模式天然处理了所有竞态和虚假唤醒。

3. post 的按旧值唤醒策略。fetch_add 返回旧值 nbutex_wake_n(butex, n) 按 n 决定唤醒数量。n==0 时唤醒所有等待者——多余的等待者在 CAS 循环中失败后重新挂起。这个设计避免了"精确唤醒"的复杂性。

4. FIFO → LIFO 防饥饿策略。 与互斥锁相同的设计:第一次等待排到队尾(公平),被唤醒后插到队头(避免被新到达者饿死)。在公平性和性能之间取得平衡。


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

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-06 23:47:35 HTTP/2.0 GET : https://67808.cn/a/486393.html
  2. 运行时间 : 0.197926s [ 吞吐率:5.05req/s ] 内存消耗:4,850.74kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=10ce0e360d817988b3f41317646868a0
  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.001141s ] mysql:host=127.0.0.1;port=3306;dbname=no_67808;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001706s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000754s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000701s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001339s ]
  6. SELECT * FROM `set` [ RunTime:0.000533s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001490s ]
  8. SELECT * FROM `article` WHERE `id` = 486393 LIMIT 1 [ RunTime:0.002880s ]
  9. UPDATE `article` SET `lasttime` = 1778082456 WHERE `id` = 486393 [ RunTime:0.007536s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 65 LIMIT 1 [ RunTime:0.000698s ]
  11. SELECT * FROM `article` WHERE `id` < 486393 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001480s ]
  12. SELECT * FROM `article` WHERE `id` > 486393 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001785s ]
  13. SELECT * FROM `article` WHERE `id` < 486393 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.005421s ]
  14. SELECT * FROM `article` WHERE `id` < 486393 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.006479s ]
  15. SELECT * FROM `article` WHERE `id` < 486393 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.005190s ]
0.201472s